2023-07-10 08:54:22 +00:00
|
|
|
package indicatorv2
|
2023-06-04 06:47:29 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/c9s/bbgo/pkg/datatype/floats"
|
2023-07-10 08:54:22 +00:00
|
|
|
"github.com/c9s/bbgo/pkg/types"
|
2023-06-04 06:47:29 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type CrossType float64
|
|
|
|
|
|
|
|
const (
|
|
|
|
CrossOver CrossType = 1.0
|
|
|
|
CrossUnder CrossType = -1.0
|
|
|
|
)
|
|
|
|
|
|
|
|
// CrossStream subscribes 2 upstreams, and calculate the cross signal
|
|
|
|
type CrossStream struct {
|
2023-07-10 08:54:22 +00:00
|
|
|
*types.Float64Series
|
2023-06-04 06:47:29 +00:00
|
|
|
|
|
|
|
a, b floats.Slice
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cross creates the CrossStream object:
|
|
|
|
//
|
|
|
|
// cross := Cross(fastEWMA, slowEWMA)
|
2023-07-10 08:54:22 +00:00
|
|
|
func Cross(a, b types.Float64Source) *CrossStream {
|
2023-06-04 06:47:29 +00:00
|
|
|
s := &CrossStream{
|
2023-07-10 08:54:22 +00:00
|
|
|
Float64Series: types.NewFloat64Series(),
|
2023-06-04 06:47:29 +00:00
|
|
|
}
|
|
|
|
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))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|