forked from c9s/bbgo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
obv.go
86 lines (68 loc) · 2.21 KB
/
obv.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package indicator
import (
"time"
"github.com/c9s/bbgo/pkg/datatype/floats"
"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.
*/
//go:generate callbackgen -type OBV
type OBV struct {
types.SeriesBase
types.IntervalWindow
Values floats.Slice
PrePrice float64
EndTime time.Time
updateCallbacks []func(value float64)
}
func (inc *OBV) Update(price, volume float64) {
if len(inc.Values) == 0 {
inc.SeriesBase.Series = inc
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)
}
}
func (inc *OBV) Last(i int) float64 {
return inc.Values.Last(i)
}
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) {
for _, k := range kLines {
if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) {
continue
}
inc.PushK(k)
}
inc.EmitUpdate(inc.Last(0))
inc.EndTime = kLines[len(kLines)-1].EndTime.Time()
}
func (inc *OBV) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) {
if inc.Interval != interval {
return
}
inc.CalculateAndUpdate(window)
}
func (inc *OBV) Bind(updater KLineWindowUpdater) {
updater.OnKLineWindowUpdate(inc.handleKLineWindowUpdate)
}