diff --git a/pkg/indicator/v2/max.go b/pkg/indicator/v2/max.go new file mode 100644 index 0000000000..5b709aca00 --- /dev/null +++ b/pkg/indicator/v2/max.go @@ -0,0 +1,33 @@ +package indicatorv2 + +import ( + "github.com/c9s/bbgo/pkg/types" +) + +// MAXStream calculates the maximum value in a window from a float number stream. +type MAXStream struct { + *types.Float64Series + + window int + rawValues *types.Queue +} + +func MAX(source types.Float64Source, window int) *MAXStream { + s := &MAXStream{ + Float64Series: types.NewFloat64Series(), + window: window, + rawValues: types.NewQueue(window), + } + + s.Bind(source, s) + return s +} + +func (s *MAXStream) Calculate(v float64) float64 { + s.rawValues.Update(v) + return types.Max(s.rawValues, s.window) +} + +func (s *MAXStream) Truncate() { + s.Slice = types.ShrinkSlice(s.Slice, MaxSliceSize, TruncateSize) +} diff --git a/pkg/indicator/v2/max_test.go b/pkg/indicator/v2/max_test.go new file mode 100644 index 0000000000..10af0919f2 --- /dev/null +++ b/pkg/indicator/v2/max_test.go @@ -0,0 +1,37 @@ +package indicatorv2 + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/types" +) + +func TestMAX(t *testing.T) { + source := types.NewFloat64Series() + maxIndicator := MAX(source, 3) + + // Test case 1: Fill the window + source.PushAndEmit(1.0) + assert.Equal(t, 1.0, maxIndicator.Last(0)) + + source.PushAndEmit(3.0) + assert.Equal(t, 3.0, maxIndicator.Last(0)) + + source.PushAndEmit(2.0) + assert.Equal(t, 3.0, maxIndicator.Last(0)) + + // Test case 2: Sliding window + source.PushAndEmit(1.0) + // Window is [3.0, 2.0, 1.0], max is 3.0 + assert.Equal(t, 3.0, maxIndicator.Last(0)) + + source.PushAndEmit(0.5) + // Window is [2.0, 1.0, 0.5], max is 2.0 + assert.Equal(t, 2.0, maxIndicator.Last(0)) + + source.PushAndEmit(4.0) + // Window is [1.0, 0.5, 4.0], max is 4.0 + assert.Equal(t, 4.0, maxIndicator.Last(0)) +}