forked from c9s/bbgo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
macd.go
135 lines (105 loc) · 2.73 KB
/
macd.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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package indicator
import (
"time"
"github.com/c9s/bbgo/pkg/types"
)
/*
macd implements moving average convergence divergence indicator
Moving Average Convergence Divergence (MACD)
- https://www.investopedia.com/terms/m/macd.asp
- https://school.stockcharts.com/doku.php?id=technical_indicators:macd-histogram
*/
//go:generate callbackgen -type MACD
type MACD struct {
types.IntervalWindow // 9
ShortPeriod int // 12
LongPeriod int // 26
Values types.Float64Slice
FastEWMA *EWMA
SlowEWMA *EWMA
SignalLine *EWMA
Histogram types.Float64Slice
EndTime time.Time
updateCallbacks []func(value float64)
}
func (inc *MACD) Update(x float64) {
if len(inc.Values) == 0 {
inc.FastEWMA = &EWMA{IntervalWindow: types.IntervalWindow{Window: inc.ShortPeriod}}
inc.SlowEWMA = &EWMA{IntervalWindow: types.IntervalWindow{Window: inc.LongPeriod}}
inc.SignalLine = &EWMA{IntervalWindow: types.IntervalWindow{Window: inc.Window}}
}
// update fast and slow ema
inc.FastEWMA.Update(x)
inc.SlowEWMA.Update(x)
// update macd
macd := inc.FastEWMA.Last() - inc.SlowEWMA.Last()
inc.Values.Push(macd)
// update signal line
inc.SignalLine.Update(macd)
// update histogram
inc.Histogram.Push(macd - inc.SignalLine.Last())
}
func (inc *MACD) Last() float64 {
if len(inc.Values) == 0 {
return 0.0
}
return inc.Values[len(inc.Values)-1]
}
func (inc *MACD) PushK(k types.KLine) {
inc.Update(k.Close.Float64())
}
func (inc *MACD) CalculateAndUpdate(allKLines []types.KLine) {
if len(allKLines) == 0 {
return
}
last := allKLines[len(allKLines)-1]
if len(inc.Values) == 0 {
for _, k := range allKLines {
if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) {
continue
}
inc.PushK(k)
}
} else {
inc.PushK(last)
}
inc.EmitUpdate(inc.Last())
inc.EndTime = last.EndTime.Time()
}
func (inc *MACD) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) {
if inc.Interval != interval {
return
}
inc.CalculateAndUpdate(window)
}
func (inc *MACD) Bind(updater KLineWindowUpdater) {
updater.OnKLineWindowUpdate(inc.handleKLineWindowUpdate)
}
type MACDValues struct {
types.SeriesBase
*MACD
}
func (inc *MACDValues) Last() float64 {
if len(inc.Values) == 0 {
return 0.0
}
return inc.Values[len(inc.Values)-1]
}
func (inc *MACDValues) Index(i int) float64 {
length := len(inc.Values)
if length == 0 || length-1-i < 0 {
return 0.0
}
return inc.Values[length-1+i]
}
func (inc *MACDValues) Length() int {
return len(inc.Values)
}
func (inc *MACD) MACD() types.SeriesExtend {
out := &MACDValues{MACD: inc}
out.SeriesBase.Series = out
return out
}
func (inc *MACD) Singals() types.SeriesExtend {
return inc.SignalLine
}