bbgo_origin/pkg/indicator/obv.go

87 lines
2.2 KiB
Go
Raw Permalink Normal View History

2021-05-10 09:17:50 +00:00
package indicator
import (
"time"
"github.com/c9s/bbgo/pkg/datatype/floats"
2021-05-10 09:17:50 +00:00
"github.com/c9s/bbgo/pkg/types"
)
/*
obv implements on-balance volume indicator
On-Balance Volume (OBV) Definition
- https://www.investopedia.com/terms/o/onbalancevolume.asp
On-Balance Volume (OBV) is a technical analysis indicator that uses volume information to predict changes in stock price.
The idea behind OBV is that volume precedes price: when the OBV is rising, it means that buyers are becoming more aggressive and
that the stock price is likely to follow suit. When the OBV is falling, it indicates that sellers are becoming more aggressive and
that the stock price is likely to decrease. OBV is calculated by adding the volume on days when the stock price closes higher and
subtracting the volume on days when the stock price closes lower. This running total forms the OBV line, which can then be used
to make predictions about future stock price movements.
2021-05-10 09:17:50 +00:00
*/
//go:generate callbackgen -type OBV
type OBV struct {
types.SeriesBase
2021-05-10 09:17:50 +00:00
types.IntervalWindow
Values floats.Slice
PrePrice float64
2022-07-13 17:16:39 +00:00
EndTime time.Time
2021-05-10 09:17:50 +00:00
2022-07-13 17:16:39 +00:00
updateCallbacks []func(value float64)
2021-05-10 09:17:50 +00:00
}
func (inc *OBV) Update(price, volume float64) {
2021-05-10 09:17:50 +00:00
if len(inc.Values) == 0 {
inc.SeriesBase.Series = inc
2021-05-10 09:17:50 +00:00
inc.PrePrice = price
inc.Values.Push(volume)
return
}
if volume < inc.PrePrice {
inc.Values.Push(inc.Last(0) - volume)
} else {
inc.Values.Push(inc.Last(0) + volume)
2021-05-10 09:17:50 +00:00
}
}
func (inc *OBV) Last(i int) float64 {
return inc.Values.Last(i)
2021-05-10 09:17:50 +00:00
}
func (inc *OBV) Index(i int) float64 {
return inc.Last(i)
}
var _ types.SeriesExtend = &OBV{}
func (inc *OBV) PushK(k types.KLine) {
inc.Update(k.Close.Float64(), k.Volume.Float64())
}
func (inc *OBV) CalculateAndUpdate(kLines []types.KLine) {
2022-03-28 19:19:29 +00:00
for _, k := range kLines {
2022-04-14 21:43:04 +00:00
if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) {
2021-05-10 09:17:50 +00:00
continue
}
inc.PushK(k)
2021-05-10 09:17:50 +00:00
}
inc.EmitUpdate(inc.Last(0))
2022-03-28 19:19:29 +00:00
inc.EndTime = kLines[len(kLines)-1].EndTime.Time()
2021-05-10 09:17:50 +00:00
}
2021-05-10 09:17:50 +00:00
func (inc *OBV) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) {
if inc.Interval != interval {
return
}
inc.CalculateAndUpdate(window)
2021-05-10 09:17:50 +00:00
}
func (inc *OBV) Bind(updater KLineWindowUpdater) {
updater.OnKLineWindowUpdate(inc.handleKLineWindowUpdate)
}