forked from sdcoffey/techan
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindicator_moving_average.go
83 lines (70 loc) · 2.96 KB
/
indicator_moving_average.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
package techan
import "github.com/sdcoffey/big"
type smaIndicator struct {
indicator Indicator
window int
}
// NewSimpleMovingAverage returns a derivative Indicator which returns the average of the current value and preceding
// values in the given window.
func NewSimpleMovingAverage(indicator Indicator, window int) Indicator {
return smaIndicator{indicator, window}
}
func (sma smaIndicator) Calculate(index int) big.Decimal {
sum := big.ZERO
for i := Max(0, index-sma.window+1); i <= index; i++ {
sum = sum.Add(sma.indicator.Calculate(i))
}
realwindow := Min(sma.window, index+1)
return sum.Div(big.NewDecimal(float64(realwindow)))
}
type emaIndicator struct {
Indicator
window int
resultCache []*big.Decimal
}
// NewEMAIndicator returns a derivative indicator which returns the average of the current and preceding values in
// the given window, with values closer to current index given more weight. A more in-depth explanation can be found here:
// http://www.investopedia.com/terms/e/ema.asp
func NewEMAIndicator(indicator Indicator, window int) Indicator {
return &emaIndicator{
Indicator: indicator,
window: window,
resultCache: make([]*big.Decimal, 10000),
}
}
func (ema *emaIndicator) Calculate(index int) big.Decimal {
if index == 0 {
result := ema.Indicator.Calculate(index)
return result
} else if index+1 < ema.window {
result := smaIndicator{ema.Indicator, ema.window}.Calculate(index)
ema.cacheResult(index, result)
return result
} else if len(ema.resultCache) > index && ema.resultCache[index] != nil {
return *ema.resultCache[index]
}
emaPrev := ema.Calculate(index - 1)
mult := big.NewDecimal(2.0 / float64(ema.window+1))
result := ema.Indicator.Calculate(index).Sub(emaPrev).Mul(mult).Add(emaPrev)
ema.cacheResult(index, result)
return result
}
func (ema *emaIndicator) cacheResult(index int, val big.Decimal) {
if index < len(ema.resultCache) {
ema.resultCache[index] = &val
} else {
ema.resultCache = append(ema.resultCache, &val)
}
}
// NewMACDIndicator returns a derivative Indicator which returns the difference between two EMAIndicators with long and
// short windows. It's useful for gauging the strength of price movements. A more in-depth explanation can be found here:
// http://www.investopedia.com/terms/m/macd.asp
func NewMACDIndicator(baseIndicator Indicator, shortwindow, longwindow int) Indicator {
return NewDifferenceIndicator(NewEMAIndicator(baseIndicator, shortwindow), NewEMAIndicator(baseIndicator, longwindow))
}
// NewMACDHistogramIndicator returns a derivative Indicator based on the MACDIndicator, the result of which is
// the macd indicator minus it's signalLinewindow EMA. A more in-depth explanation can be found here:
// http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:macd-histogram
func NewMACDHistogramIndicator(macdIdicator Indicator, signalLinewindow int) Indicator {
return NewDifferenceIndicator(macdIdicator, NewEMAIndicator(macdIdicator, signalLinewindow))
}