diff --git a/pkg/indicator/rma.go b/pkg/indicator/rma.go new file mode 100644 index 000000000..19124e491 --- /dev/null +++ b/pkg/indicator/rma.go @@ -0,0 +1,76 @@ +package indicator + +import ( + "time" + + "github.com/c9s/bbgo/pkg/types" +) + +//go:generate callbackgen -type RMA +type RMA struct { + types.IntervalWindow + Values types.Float64Slice + Sources types.Float64Slice + + EndTime time.Time + UpdateCallbacks []func(value float64) +} + +func (inc *RMA) Update(x float64) { + inc.Sources.Push(x) + + if len(inc.Sources) < inc.Window { + inc.Values.Push(0) + return + } + + if len(inc.Sources) == inc.Window { + inc.Values.Push(inc.Sources.Mean()) + return + } + + lambda := 1 / float64(inc.Window) + rma := (1-lambda)*inc.Values.Last() + lambda*x + inc.Values.Push(rma) +} + +func (inc *RMA) Last() float64 { + return inc.Values.Last() +} + +func (inc *RMA) Index(i int) float64 { + length := len(inc.Values) + if length == 0 || length-i-1 < 0 { + return 0 + } + return inc.Values[length-i-1] +} + +func (inc *RMA) Length() int { + return len(inc.Values) +} + +var _ types.Series = &RMA{} + +func (inc *RMA) calculateAndUpdate(kLines []types.KLine) { + for _, k := range kLines { + if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) { + continue + } + inc.Update(k.Close.Float64()) + } + + inc.EmitUpdate(inc.Last()) + inc.EndTime = kLines[len(kLines)-1].EndTime.Time() +} +func (inc *RMA) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) { + if inc.Interval != interval { + return + } + + inc.calculateAndUpdate(window) +} + +func (inc *RMA) Bind(updater KLineWindowUpdater) { + updater.OnKLineWindowUpdate(inc.handleKLineWindowUpdate) +} diff --git a/pkg/indicator/rma_callbacks.go b/pkg/indicator/rma_callbacks.go new file mode 100644 index 000000000..f5a40ca5e --- /dev/null +++ b/pkg/indicator/rma_callbacks.go @@ -0,0 +1,15 @@ +// Code generated by "callbackgen -type RMA"; DO NOT EDIT. + +package indicator + +import () + +func (inc *RMA) OnUpdate(cb func(value float64)) { + inc.UpdateCallbacks = append(inc.UpdateCallbacks, cb) +} + +func (inc *RMA) EmitUpdate(value float64) { + for _, cb := range inc.UpdateCallbacks { + cb(value) + } +}