-
Notifications
You must be signed in to change notification settings - Fork 0
/
macd.go
129 lines (101 loc) · 3.19 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
package indicator
import (
"time"
"github.com/c9s/bbgo/pkg/datatype/floats"
"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
// The Moving Average Convergence Divergence (MACD) is a technical analysis indicator that is used to measure the relationship between
// two moving averages of a security's price. It is calculated by subtracting the longer-term moving average from the shorter-term moving
// average, and then plotting the resulting value on the price chart as a line. This line is known as the MACD line, and is typically
// used to identify potential buy or sell signals. The MACD is typically used in conjunction with a signal line, which is a moving average
// of the MACD line, to generate more accurate buy and sell signals.
type MACDConfig struct {
types.IntervalWindow // 9
// ShortPeriod is the short term period EMA, usually 12
ShortPeriod int `json:"short"`
// LongPeriod is the long term period EMA, usually 26
LongPeriod int `json:"long"`
}
//go:generate callbackgen -type MACD
type MACD struct {
MACDConfig
Values floats.Slice `json:"-"`
fastEWMA, slowEWMA, signalLine *EWMA
Histogram floats.Slice `json:"-"`
EndTime time.Time
updateCallbacks []func(macd, signal, histogram float64)
}
func (inc *MACD) Update(x float64) {
if len(inc.Values) == 0 {
// apply default values
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}}
if inc.ShortPeriod == 0 {
inc.ShortPeriod = 12
}
if inc.LongPeriod == 0 {
inc.LongPeriod = 26
}
}
// update fast and slow ema
inc.fastEWMA.Update(x)
inc.slowEWMA.Update(x)
// update MACD value, it's also the signal line
fast := inc.fastEWMA.Last()
slow := inc.slowEWMA.Last()
macd := fast - slow
inc.Values.Push(macd)
// update signal line
inc.signalLine.Update(macd)
signal := inc.signalLine.Last()
// update histogram
histogram := macd - signal
inc.Histogram.Push(histogram)
inc.EmitUpdate(macd, signal, histogram)
}
func (inc *MACD) Last() float64 {
if len(inc.Values) == 0 {
return 0.0
}
return inc.Values[len(inc.Values)-1]
}
func (inc *MACD) Length() int {
return len(inc.Values)
}
func (inc *MACD) PushK(k types.KLine) {
inc.Update(k.Close.Float64())
}
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
}
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)
}