-
Notifications
You must be signed in to change notification settings - Fork 0
/
macd.go
138 lines (118 loc) · 3.39 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
136
137
138
package shingo
import (
"math"
"time"
"github.com/pkg/errors"
)
// AppendMACD appends Moving Average Convergence Divergence indicators to each candlestick
func (cs *Candlesticks) AppendMACD(args IndicatorInputArg) error {
period1 := args.MacdLarge
period2 := args.MacdSmall
signalLine := args.MacdSignal
limit := args.Limit
if period1 == 0 {
return errors.New("MacdLarge must be greater than zero")
}
if period2 == 0 {
return errors.New("MacdSmall must be greater than zero")
}
if signalLine == 0 {
return errors.New("signalLine must be greater than zero")
}
if period1 >= period2 {
return errors.New("Period1 must be less than Period2 in MACD")
}
cs.mux.Lock()
defer cs.mux.Unlock()
cl := cs.Total()
if cl < 1 {
return nil
}
if limit < 1 {
limit = cs.Total()
}
if err := cs.GenerateIndicator(IndicatorTypeEMA, IndicatorInputArg{
Period: period1,
Limit: cl,
}); err != nil {
return errors.Wrap(err, "Error generating period1 indicator")
}
if err := cs.GenerateIndicator(IndicatorTypeEMA, IndicatorInputArg{
Period: period2,
Limit: cl,
}); err != nil {
return errors.Wrap(err, "Error generating period2 indicator")
}
cst, err := NewCandlesticks(IntervalOneDay, 100)
if err != nil {
return errors.Wrap(err, "Error creating candlesticks for macd signal line")
}
for i := 0; i < cl; i++ {
v := cs.ItemAtIndex(i)
ema1 := v.GetEMA(period1)
ema2 := v.GetEMA(period2)
if ema1 == nil || ema2 == nil {
continue
}
val := ema1.Value - ema2.Value
c, err := NewCandlestick(0, val, 0, 0, time.Time{}, 0)
if err != nil {
return errors.Wrap(err, "Error creating candlestick in macd signal line")
}
cst.AppendCandlestick(c)
}
cstl := cst.Total()
err = cst.GenerateIndicator(IndicatorTypeEMA, IndicatorInputArg{
Period: signalLine,
Limit: cl,
})
if err != nil {
return errors.Wrap(err, "Error creating ema for macd signal line")
}
endIdx := cl - cstl
var count int
for i := cl - 1; i >= endIdx; i-- {
if count == limit {
return nil
}
v := cs.ItemAtIndex(i)
ci := int(math.Abs(float64(cl - i - cstl)))
vi := cst.ItemAtIndex(ci)
if vi != nil && vi.GetEMA(signalLine) == nil {
continue
}
macdValue := v.GetEMA(period1).Value - v.GetEMA(period2).Value
signalValue := vi.GetEMA(signalLine).Value
v.setMACD(period1, period2, signalLine, macdValue, signalValue)
count++
}
return nil
}
// GetMACD gets MACD value for this candlestick given fast, slow and signal line value
func (c *Candlestick) GetMACD(period1, period2, signal int) *MACDDelta {
if c.Indicators == nil || c.Indicators.MACDs == nil {
return nil
}
if c.Indicators.MACDs[period1] == nil || c.Indicators.MACDs[period1][period2] == nil {
return nil
}
return c.Indicators.MACDs[period1][period2][signal]
}
func (c *Candlestick) setMACD(period1 int, period2 int, signal int, macdValue float64, signalValue float64) {
if c.Indicators.MACDs == nil {
c.Indicators.MACDs = make(map[int]map[int]map[int]*MACDDelta)
}
if c.Indicators.MACDs[period1] == nil {
c.Indicators.MACDs[period1] = make(map[int]map[int]*MACDDelta)
}
if c.Indicators.MACDs[period1][period2] == nil {
c.Indicators.MACDs[period1][period2] = make(map[int]*MACDDelta)
}
if c.Indicators.MACDs[period1][period2][signal] == nil {
c.Indicators.MACDs[period1][period2][signal] = &MACDDelta{
MACDValue: macdValue,
SignalValue: signalValue,
MACDHistogram: macdValue - signalValue,
}
}
}