mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-22 14:55:16 +00:00
indicator: add cross stream
This commit is contained in:
parent
7f3f2c1217
commit
ca78a3379a
71
pkg/indicator/float64series.go
Normal file
71
pkg/indicator/float64series.go
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
package indicator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/c9s/bbgo/pkg/datatype/floats"
|
||||||
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Float64Series struct {
|
||||||
|
types.SeriesBase
|
||||||
|
Float64Updater
|
||||||
|
slice floats.Slice
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFloat64Series(v ...float64) Float64Series {
|
||||||
|
s := Float64Series{}
|
||||||
|
s.slice = v
|
||||||
|
s.SeriesBase.Series = s.slice
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Float64Series) Last(i int) float64 {
|
||||||
|
return f.slice.Last(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Float64Series) Index(i int) float64 {
|
||||||
|
return f.Last(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Float64Series) Length() int {
|
||||||
|
return len(f.slice)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Float64Series) Slice() floats.Slice {
|
||||||
|
return f.slice
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Float64Series) PushAndEmit(x float64) {
|
||||||
|
f.slice.Push(x)
|
||||||
|
f.EmitUpdate(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Float64Series) Subscribe(source Float64Source, c func(x float64)) {
|
||||||
|
if sub, ok := source.(Float64Subscription); ok {
|
||||||
|
sub.AddSubscriber(c)
|
||||||
|
} else {
|
||||||
|
source.OnUpdate(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind binds the source event to the target (Float64Calculator)
|
||||||
|
// A Float64Calculator should be able to calculate the float64 result from a single float64 argument input
|
||||||
|
func (f *Float64Series) Bind(source Float64Source, target Float64Calculator) {
|
||||||
|
var c func(x float64)
|
||||||
|
|
||||||
|
// optimize the truncation check
|
||||||
|
trc, canTruncate := target.(Float64Truncator)
|
||||||
|
if canTruncate {
|
||||||
|
c = func(x float64) {
|
||||||
|
y := target.Calculate(x)
|
||||||
|
target.PushAndEmit(y)
|
||||||
|
trc.Truncate()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c = func(x float64) {
|
||||||
|
y := target.Calculate(x)
|
||||||
|
target.PushAndEmit(y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Subscribe(source, c)
|
||||||
|
}
|
|
@ -1,76 +1,6 @@
|
||||||
package indicator
|
package indicator
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/c9s/bbgo/pkg/datatype/floats"
|
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:generate callbackgen -type Float64Updater
|
//go:generate callbackgen -type Float64Updater
|
||||||
type Float64Updater struct {
|
type Float64Updater struct {
|
||||||
updateCallbacks []func(v float64)
|
updateCallbacks []func(v float64)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Float64Series struct {
|
|
||||||
types.SeriesBase
|
|
||||||
Float64Updater
|
|
||||||
slice floats.Slice
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewFloat64Series(v ...float64) Float64Series {
|
|
||||||
s := Float64Series{}
|
|
||||||
s.slice = v
|
|
||||||
s.SeriesBase.Series = s.slice
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Float64Series) Last(i int) float64 {
|
|
||||||
return f.slice.Last(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Float64Series) Index(i int) float64 {
|
|
||||||
return f.Last(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Float64Series) Length() int {
|
|
||||||
return len(f.slice)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Float64Series) Slice() floats.Slice {
|
|
||||||
return f.slice
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Float64Series) PushAndEmit(x float64) {
|
|
||||||
f.slice.Push(x)
|
|
||||||
f.EmitUpdate(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Float64Series) Subscribe(source Float64Source, c func(x float64)) {
|
|
||||||
if sub, ok := source.(Float64Subscription); ok {
|
|
||||||
sub.AddSubscriber(c)
|
|
||||||
} else {
|
|
||||||
source.OnUpdate(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind binds the source event to the target (Float64Calculator)
|
|
||||||
// A Float64Calculator should be able to calculate the float64 result from a single float64 argument input
|
|
||||||
func (f *Float64Series) Bind(source Float64Source, target Float64Calculator) {
|
|
||||||
var c func(x float64)
|
|
||||||
|
|
||||||
// optimize the truncation check
|
|
||||||
trc, canTruncate := target.(Float64Truncator)
|
|
||||||
if canTruncate {
|
|
||||||
c = func(x float64) {
|
|
||||||
y := target.Calculate(x)
|
|
||||||
target.PushAndEmit(y)
|
|
||||||
trc.Truncate()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
c = func(x float64) {
|
|
||||||
y := target.Calculate(x)
|
|
||||||
target.PushAndEmit(y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Subscribe(source, c)
|
|
||||||
}
|
|
||||||
|
|
59
pkg/indicator/v2_cross.go
Normal file
59
pkg/indicator/v2_cross.go
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package indicator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/c9s/bbgo/pkg/datatype/floats"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CrossType float64
|
||||||
|
|
||||||
|
const (
|
||||||
|
CrossOver CrossType = 1.0
|
||||||
|
CrossUnder CrossType = -1.0
|
||||||
|
)
|
||||||
|
|
||||||
|
// CrossStream subscribes 2 upstreams, and calculate the cross signal
|
||||||
|
type CrossStream struct {
|
||||||
|
Float64Series
|
||||||
|
|
||||||
|
a, b floats.Slice
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cross creates the CrossStream object:
|
||||||
|
//
|
||||||
|
// cross := Cross(fastEWMA, slowEWMA)
|
||||||
|
func Cross(a, b Float64Source) *CrossStream {
|
||||||
|
s := &CrossStream{
|
||||||
|
Float64Series: NewFloat64Series(),
|
||||||
|
}
|
||||||
|
a.OnUpdate(func(v float64) {
|
||||||
|
s.a.Push(v)
|
||||||
|
s.calculate()
|
||||||
|
})
|
||||||
|
b.OnUpdate(func(v float64) {
|
||||||
|
s.b.Push(v)
|
||||||
|
s.calculate()
|
||||||
|
})
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CrossStream) calculate() {
|
||||||
|
if s.a.Length() != s.b.Length() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
current := s.a.Last(0) - s.b.Last(0)
|
||||||
|
previous := s.a.Last(1) - s.b.Last(1)
|
||||||
|
|
||||||
|
if previous == 0.0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// cross over or cross under
|
||||||
|
if current*previous < 0 {
|
||||||
|
if current > 0 {
|
||||||
|
s.PushAndEmit(float64(CrossOver))
|
||||||
|
} else {
|
||||||
|
s.PushAndEmit(float64(CrossUnder))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user