mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +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
|
||||
|
||||
import (
|
||||
"github.com/c9s/bbgo/pkg/datatype/floats"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
)
|
||||
|
||||
//go:generate callbackgen -type Float64Updater
|
||||
type Float64Updater struct {
|
||||
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