diff --git a/pkg/indicator/v2/smma.go b/pkg/indicator/v2/smma.go new file mode 100644 index 0000000000..2925feca9b --- /dev/null +++ b/pkg/indicator/v2/smma.go @@ -0,0 +1,47 @@ +package indicatorv2 + +import ( + "github.com/c9s/bbgo/pkg/types" +) + +type SMMAStream struct { + *types.Float64Series + window int + rawValues *types.Queue + source types.Float64Source +} + +func SMMA2(source types.Float64Source, window int) *SMMAStream { + s := &SMMAStream{ + Float64Series: types.NewFloat64Series(), + window: window, + rawValues: types.NewQueue(window), + source: source, + } + s.Bind(source, s) + return s +} + +func (s *SMMAStream) Calculate(v float64) float64 { + var out float64 + sourceLen := s.source.Length() + + if sourceLen < s.window { + // Until we reach the end of the period, sum the prices. + + // First, calculate the sum, and it will be automatically saved too. + s.rawValues.Sum(s.window) + // Then save the input value to use it later on. + s.rawValues.Update(v) + } else if sourceLen == s.window { + // We need the SMA for the first time. + s.rawValues.Update(v) + out = s.rawValues.Mean(s.window) + } else { + // For all the rest values, just use the formula. + last := s.Slice.Last(0) + out = (last*float64((s.window-1.0)) + v) / float64(s.window) + } + + return out +} diff --git a/pkg/indicator/v2/smma_test.go b/pkg/indicator/v2/smma_test.go new file mode 100644 index 0000000000..08c114b384 --- /dev/null +++ b/pkg/indicator/v2/smma_test.go @@ -0,0 +1,27 @@ +package indicatorv2 + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/types" +) + +func TestSMMA(t *testing.T) { + source := types.NewFloat64Series() + smma := SMMA2(source, 3) + + data := []float64{10, 20, 30, 40, 50, 60, 70, 80, 90} + for _, d := range data { + source.PushAndEmit(d) + } + + // Assert the first 3 and last 3 value outputs. + assert.InDelta(t, 0, smma.Last(len(data)-1), 0.001) + assert.InDelta(t, 0, smma.Last(len(data)-2), 0.001) + assert.InDelta(t, 20, smma.Last(len(data)-3), 0.001) + assert.InDelta(t, 51.97530864197531, smma.Last(2), 0.001) + assert.InDelta(t, 61.31687242798355, smma.Last(1), 0.001) + assert.InDelta(t, 70.87791495198904, smma.Last(0), 0.001) +}