macd works with test.
This commit is contained in:
parent
4f8680a2b1
commit
98c46b62d2
4 changed files with 157 additions and 88 deletions
|
@ -11,8 +11,6 @@ type EMASeries struct {
|
||||||
Style Style
|
Style Style
|
||||||
YAxis YAxisType
|
YAxis YAxisType
|
||||||
|
|
||||||
// Sigma is the 'smoothing factor' parameter.
|
|
||||||
Sigma float64
|
|
||||||
Period int
|
Period int
|
||||||
InnerSeries ValueProvider
|
InnerSeries ValueProvider
|
||||||
}
|
}
|
||||||
|
@ -49,14 +47,8 @@ func (ema EMASeries) Len() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSigma returns the smoothing factor for the serise.
|
// GetSigma returns the smoothing factor for the serise.
|
||||||
func (ema EMASeries) GetSigma(defaults ...float64) float64 {
|
func (ema EMASeries) GetSigma() float64 {
|
||||||
if ema.Sigma == 0 {
|
return 2.0 / (float64(ema.Period) + 1)
|
||||||
if len(defaults) > 0 {
|
|
||||||
return defaults[0]
|
|
||||||
}
|
|
||||||
return DefaultEMASigma
|
|
||||||
}
|
|
||||||
return ema.Sigma
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetValue gets a value at a given index.
|
// GetValue gets a value at a given index.
|
||||||
|
@ -84,11 +76,11 @@ func (ema EMASeries) GetLastValue() (x float64, y float64) {
|
||||||
|
|
||||||
func (ema EMASeries) compute(period, index int) float64 {
|
func (ema EMASeries) compute(period, index int) float64 {
|
||||||
_, v := ema.InnerSeries.GetValue(index)
|
_, v := ema.InnerSeries.GetValue(index)
|
||||||
if period == 1 || index == 0 {
|
if index == 0 {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
sig := ema.GetSigma()
|
previousEMA := ema.compute(period-1, index-1)
|
||||||
return sig*v + ((1.0 - sig) * ema.compute(period-1, index-1))
|
return ((v - previousEMA) * ema.GetSigma()) + previousEMA
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render renders the series.
|
// Render renders the series.
|
||||||
|
|
|
@ -1,35 +1,105 @@
|
||||||
package chart
|
package chart
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/blendlabs/go-assert"
|
"github.com/blendlabs/go-assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
emaXValues = Seq(1.0, 50.0)
|
||||||
|
emaYValues = []float64{
|
||||||
|
1, 2, 3, 4, 5, 4, 3, 2,
|
||||||
|
1, 2, 3, 4, 5, 4, 3, 2,
|
||||||
|
1, 2, 3, 4, 5, 4, 3, 2,
|
||||||
|
1, 2, 3, 4, 5, 4, 3, 2,
|
||||||
|
1, 2, 3, 4, 5, 4, 3, 2,
|
||||||
|
1, 2, 3, 4, 5, 4, 3, 2,
|
||||||
|
1, 2,
|
||||||
|
}
|
||||||
|
emaExpected = []float64{
|
||||||
|
1,
|
||||||
|
1.074074074,
|
||||||
|
1.216735254,
|
||||||
|
1.422903013,
|
||||||
|
1.68787316,
|
||||||
|
1.859141815,
|
||||||
|
1.943649828,
|
||||||
|
1.947823915,
|
||||||
|
1.877614736,
|
||||||
|
1.886680311,
|
||||||
|
1.969148437,
|
||||||
|
2.119581886,
|
||||||
|
2.33294619,
|
||||||
|
2.456431658,
|
||||||
|
2.496695979,
|
||||||
|
2.459903685,
|
||||||
|
2.351762671,
|
||||||
|
2.325706177,
|
||||||
|
2.375653867,
|
||||||
|
2.495975803,
|
||||||
|
2.681459077,
|
||||||
|
2.779128775,
|
||||||
|
2.795489607,
|
||||||
|
2.73656445,
|
||||||
|
2.607930047,
|
||||||
|
2.562898191,
|
||||||
|
2.595276103,
|
||||||
|
2.699329725,
|
||||||
|
2.869749746,
|
||||||
|
2.953471987,
|
||||||
|
2.956918506,
|
||||||
|
2.886035654,
|
||||||
|
2.746329309,
|
||||||
|
2.691045657,
|
||||||
|
2.713931163,
|
||||||
|
2.809195522,
|
||||||
|
2.971477335,
|
||||||
|
3.047664199,
|
||||||
|
3.044133518,
|
||||||
|
2.966790294,
|
||||||
|
2.821102124,
|
||||||
|
2.760279745,
|
||||||
|
2.778036801,
|
||||||
|
2.868552593,
|
||||||
|
3.026437586,
|
||||||
|
3.098553321,
|
||||||
|
3.091253075,
|
||||||
|
3.010419514,
|
||||||
|
2.86149955,
|
||||||
|
2.797684768,
|
||||||
|
}
|
||||||
|
emaDelta = 0.0001
|
||||||
|
)
|
||||||
|
|
||||||
func TestEMASeries(t *testing.T) {
|
func TestEMASeries(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
mockSeries := mockValueProvider{
|
mockSeries := mockValueProvider{
|
||||||
Seq(1.0, 10.0),
|
emaXValues,
|
||||||
Seq(10, 1.0),
|
emaYValues,
|
||||||
}
|
}
|
||||||
assert.Equal(10, mockSeries.Len())
|
assert.Equal(50, mockSeries.Len())
|
||||||
|
|
||||||
mas := &EMASeries{
|
ema := &EMASeries{
|
||||||
InnerSeries: mockSeries,
|
InnerSeries: mockSeries,
|
||||||
|
Period: 26,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sig := ema.GetSigma()
|
||||||
|
assert.Equal(2.0/(26.0+1), sig)
|
||||||
|
|
||||||
var yvalues []float64
|
var yvalues []float64
|
||||||
for x := 0; x < mas.Len(); x++ {
|
for x := 0; x < ema.Len(); x++ {
|
||||||
_, y := mas.GetValue(x)
|
_, y := ema.GetValue(x)
|
||||||
yvalues = append(yvalues, y)
|
yvalues = append(yvalues, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(10.0, yvalues[0])
|
for index, yv := range yvalues {
|
||||||
assert.True(math.Abs(yvalues[9]-3.77) < 0.01)
|
assert.InDelta(yv, emaExpected[index], emaDelta)
|
||||||
|
}
|
||||||
lvx, lvy := mas.GetLastValue()
|
|
||||||
assert.Equal(10.0, lvx)
|
lvx, lvy := ema.GetLastValue()
|
||||||
assert.True(math.Abs(lvy-3.77) < 0.01)
|
assert.Equal(50.0, lvx)
|
||||||
|
assert.InDelta(lvy, emaExpected[49], emaDelta)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,6 @@ type MACDSeries struct {
|
||||||
PrimaryPeriod int
|
PrimaryPeriod int
|
||||||
SecondaryPeriod int
|
SecondaryPeriod int
|
||||||
SignalPeriod int
|
SignalPeriod int
|
||||||
|
|
||||||
Sigma float64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPeriods returns the primary and secondary periods.
|
// GetPeriods returns the primary and secondary periods.
|
||||||
|
@ -44,17 +42,6 @@ func (macd MACDSeries) GetPeriods() (w1, w2, sig int) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSigma returns the smoothing factor for the serise.
|
|
||||||
func (macd MACDSeries) GetSigma(defaults ...float64) float64 {
|
|
||||||
if macd.Sigma == 0 {
|
|
||||||
if len(defaults) > 0 {
|
|
||||||
return defaults[0]
|
|
||||||
}
|
|
||||||
return DefaultEMASigma
|
|
||||||
}
|
|
||||||
return macd.Sigma
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetName returns the name of the time series.
|
// GetName returns the name of the time series.
|
||||||
func (macd MACDSeries) GetName() string {
|
func (macd MACDSeries) GetName() string {
|
||||||
return macd.Name
|
return macd.Name
|
||||||
|
@ -76,12 +63,7 @@ func (macd MACDSeries) Len() int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
w1, _, _ := macd.GetPeriods()
|
return macd.InnerSeries.Len()
|
||||||
innerLen := macd.InnerSeries.Len()
|
|
||||||
if innerLen > w1 {
|
|
||||||
return innerLen - w1
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetValue gets a value at a given index. For MACD it is the signal value.
|
// GetValue gets a value at a given index. For MACD it is the signal value.
|
||||||
|
@ -91,19 +73,15 @@ func (macd MACDSeries) GetValue(index int) (x float64, y float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
w1, w2, sig := macd.GetPeriods()
|
w1, w2, sig := macd.GetPeriods()
|
||||||
sigma := macd.GetSigma()
|
|
||||||
|
|
||||||
effectiveIndex := index + w1
|
x, _ = macd.InnerSeries.GetValue(index)
|
||||||
x, _ = macd.InnerSeries.GetValue(effectiveIndex)
|
|
||||||
|
|
||||||
signal := EMASeries{
|
signal := EMASeries{
|
||||||
InnerSeries: MACDLineSeries{
|
InnerSeries: MACDLineSeries{
|
||||||
InnerSeries: macd.InnerSeries,
|
InnerSeries: macd.InnerSeries,
|
||||||
PrimaryPeriod: w1,
|
PrimaryPeriod: w1,
|
||||||
SecondaryPeriod: w2,
|
SecondaryPeriod: w2,
|
||||||
Sigma: sigma,
|
|
||||||
},
|
},
|
||||||
Sigma: sigma,
|
|
||||||
Period: sig,
|
Period: sig,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,11 +89,10 @@ func (macd MACDSeries) GetValue(index int) (x float64, y float64) {
|
||||||
InnerSeries: macd.InnerSeries,
|
InnerSeries: macd.InnerSeries,
|
||||||
PrimaryPeriod: w1,
|
PrimaryPeriod: w1,
|
||||||
SecondaryPeriod: w2,
|
SecondaryPeriod: w2,
|
||||||
Sigma: sigma,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, sv := signal.GetValue(index)
|
|
||||||
_, lv := macdl.GetValue(index)
|
_, lv := macdl.GetValue(index)
|
||||||
|
_, sv := signal.GetValue(index)
|
||||||
y = lv - sv
|
y = lv - sv
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -131,8 +108,6 @@ type MACDSignalSeries struct {
|
||||||
PrimaryPeriod int
|
PrimaryPeriod int
|
||||||
SecondaryPeriod int
|
SecondaryPeriod int
|
||||||
SignalPeriod int
|
SignalPeriod int
|
||||||
|
|
||||||
Sigma float64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPeriods returns the primary and secondary periods.
|
// GetPeriods returns the primary and secondary periods.
|
||||||
|
@ -155,17 +130,6 @@ func (macds MACDSignalSeries) GetPeriods() (w1, w2, sig int) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSigma returns the smoothing factor for the serise.
|
|
||||||
func (macds MACDSignalSeries) GetSigma(defaults ...float64) float64 {
|
|
||||||
if macds.Sigma == 0 {
|
|
||||||
if len(defaults) > 0 {
|
|
||||||
return defaults[0]
|
|
||||||
}
|
|
||||||
return DefaultEMASigma
|
|
||||||
}
|
|
||||||
return macds.Sigma
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetName returns the name of the time series.
|
// GetName returns the name of the time series.
|
||||||
func (macds MACDSignalSeries) GetName() string {
|
func (macds MACDSignalSeries) GetName() string {
|
||||||
return macds.Name
|
return macds.Name
|
||||||
|
@ -187,12 +151,7 @@ func (macds MACDSignalSeries) Len() int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
w1, _, _ := macds.GetPeriods()
|
return macds.InnerSeries.Len()
|
||||||
innerLen := macds.InnerSeries.Len()
|
|
||||||
if innerLen > w1 {
|
|
||||||
return innerLen - w1
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetValue gets a value at a given index. For MACD it is the signal value.
|
// GetValue gets a value at a given index. For MACD it is the signal value.
|
||||||
|
@ -202,19 +161,15 @@ func (macds MACDSignalSeries) GetValue(index int) (x float64, y float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
w1, w2, sig := macds.GetPeriods()
|
w1, w2, sig := macds.GetPeriods()
|
||||||
sigma := macds.GetSigma()
|
|
||||||
|
|
||||||
effectiveIndex := index + w1
|
x, _ = macds.InnerSeries.GetValue(index)
|
||||||
x, _ = macds.InnerSeries.GetValue(effectiveIndex)
|
|
||||||
|
|
||||||
signal := EMASeries{
|
signal := EMASeries{
|
||||||
InnerSeries: MACDLineSeries{
|
InnerSeries: MACDLineSeries{
|
||||||
InnerSeries: macds.InnerSeries,
|
InnerSeries: macds.InnerSeries,
|
||||||
PrimaryPeriod: w1,
|
PrimaryPeriod: w1,
|
||||||
SecondaryPeriod: w2,
|
SecondaryPeriod: w2,
|
||||||
Sigma: sigma,
|
|
||||||
},
|
},
|
||||||
Sigma: sigma,
|
|
||||||
Period: sig,
|
Period: sig,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,12 +232,7 @@ func (macdl MACDLineSeries) Len() int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
w1, _ := macdl.GetPeriods()
|
return macdl.InnerSeries.Len()
|
||||||
innerLen := macdl.InnerSeries.Len()
|
|
||||||
if innerLen > w1 {
|
|
||||||
return innerLen - w1
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSigma returns the smoothing factor for the serise.
|
// GetSigma returns the smoothing factor for the serise.
|
||||||
|
@ -304,19 +254,16 @@ func (macdl MACDLineSeries) GetValue(index int) (x float64, y float64) {
|
||||||
|
|
||||||
w1, w2 := macdl.GetPeriods()
|
w1, w2 := macdl.GetPeriods()
|
||||||
|
|
||||||
effectiveIndex := index + w1
|
x, _ = macdl.InnerSeries.GetValue(index)
|
||||||
x, _ = macdl.InnerSeries.GetValue(effectiveIndex)
|
|
||||||
|
|
||||||
ema1 := EMASeries{
|
ema1 := EMASeries{
|
||||||
InnerSeries: macdl.InnerSeries,
|
InnerSeries: macdl.InnerSeries,
|
||||||
Period: w1,
|
Period: w1,
|
||||||
Sigma: macdl.GetSigma(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ema2 := EMASeries{
|
ema2 := EMASeries{
|
||||||
InnerSeries: macdl.InnerSeries,
|
InnerSeries: macdl.InnerSeries,
|
||||||
Period: w2,
|
Period: w2,
|
||||||
Sigma: macdl.GetSigma(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, emav1 := ema1.GetValue(index)
|
_, emav1 := ema1.GetValue(index)
|
||||||
|
|
|
@ -1,19 +1,75 @@
|
||||||
package chart
|
package chart
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/blendlabs/go-assert"
|
"github.com/blendlabs/go-assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
macdExpected = []float64{
|
||||||
|
0,
|
||||||
|
-0.06381766382,
|
||||||
|
-0.1641441222,
|
||||||
|
-0.2817201894,
|
||||||
|
-0.4033023481,
|
||||||
|
-0.3924673744,
|
||||||
|
-0.2983093823,
|
||||||
|
-0.1561821464,
|
||||||
|
0.008916708129,
|
||||||
|
0.05210332292,
|
||||||
|
0.01649503993,
|
||||||
|
-0.06667130899,
|
||||||
|
-0.1751344574,
|
||||||
|
-0.1657328378,
|
||||||
|
-0.08257097469,
|
||||||
|
0.04265109369,
|
||||||
|
0.1875741257,
|
||||||
|
0.2091853882,
|
||||||
|
0.1518975486,
|
||||||
|
0.04781419838,
|
||||||
|
-0.08025242841,
|
||||||
|
-0.08881960494,
|
||||||
|
-0.02183529775,
|
||||||
|
0.08904155476,
|
||||||
|
0.2214141128,
|
||||||
|
0.2321805992,
|
||||||
|
0.1656331722,
|
||||||
|
0.05373789678,
|
||||||
|
-0.08083727586,
|
||||||
|
-0.09475354363,
|
||||||
|
-0.03209767112,
|
||||||
|
0.07534076818,
|
||||||
|
0.2050442354,
|
||||||
|
0.2138010557,
|
||||||
|
0.1458045181,
|
||||||
|
0.03293263556,
|
||||||
|
-0.1022243734,
|
||||||
|
-0.1163957964,
|
||||||
|
-0.05372761902,
|
||||||
|
0.05393941791,
|
||||||
|
0.1840438454,
|
||||||
|
0.1933365048,
|
||||||
|
0.1259788988,
|
||||||
|
0.01382225715,
|
||||||
|
-0.1205656194,
|
||||||
|
-0.1339326478,
|
||||||
|
-0.07044017167,
|
||||||
|
0.03805851969,
|
||||||
|
0.1689918111,
|
||||||
|
0.1791024416,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func TestMACDSeries(t *testing.T) {
|
func TestMACDSeries(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
mockSeries := mockValueProvider{
|
mockSeries := mockValueProvider{
|
||||||
Seq(1.0, 100.0),
|
emaXValues,
|
||||||
SeqRand(100.0, 256),
|
emaYValues,
|
||||||
}
|
}
|
||||||
assert.Equal(100, mockSeries.Len())
|
assert.Equal(50, mockSeries.Len())
|
||||||
|
|
||||||
mas := &MACDSeries{
|
mas := &MACDSeries{
|
||||||
InnerSeries: mockSeries,
|
InnerSeries: mockSeries,
|
||||||
|
@ -26,4 +82,8 @@ func TestMACDSeries(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.NotEmpty(yvalues)
|
assert.NotEmpty(yvalues)
|
||||||
|
for index, vy := range yvalues {
|
||||||
|
fmt.Printf("delta @ %d actual: %0.9f expected: %0.9f\n", index, vy, macdExpected[index])
|
||||||
|
assert.InDelta(vy, macdExpected[index], emaDelta, fmt.Sprintf("delta @ %d actual: %0.9f expected: %0.9f", index, vy, macdExpected[index]))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue