Skip to content

Commit e4d4a5d

Browse files
committed
Implement Stochastic RSI Indicator
1 parent a2f4ef8 commit e4d4a5d

2 files changed

Lines changed: 147 additions & 0 deletions

File tree

indicator_stochastic_rsi.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package techan
2+
3+
import (
4+
"math"
5+
6+
"github.com/sdcoffey/big"
7+
)
8+
9+
type stochasticRSIIndicator struct {
10+
curRSI Indicator
11+
minRSI Indicator
12+
maxRSI Indicator
13+
}
14+
15+
// NewStochasticRSIIndicator returns a derivative Indicator which returns the stochastic RSI indicator for the given
16+
// RSI window.
17+
// https://www.investopedia.com/terms/s/stochrsi.asp
18+
func NewStochasticRSIIndicator(indicator Indicator, timeframe int) Indicator {
19+
rsiIndicator := NewRelativeStrengthIndexIndicator(indicator, timeframe)
20+
return stochasticRSIIndicator{
21+
curRSI: rsiIndicator,
22+
minRSI: NewMinimumValueIndicator(rsiIndicator, timeframe),
23+
maxRSI: NewMaximumValueIndicator(rsiIndicator, timeframe),
24+
}
25+
}
26+
27+
func (sri stochasticRSIIndicator) Calculate(index int) big.Decimal {
28+
curRSI := sri.curRSI.Calculate(index)
29+
minRSI := sri.minRSI.Calculate(index)
30+
maxRSI := sri.maxRSI.Calculate(index)
31+
32+
if minRSI.EQ(maxRSI) {
33+
return big.NewDecimal(math.Inf(1))
34+
}
35+
36+
return curRSI.Sub(minRSI).Div(maxRSI.Sub(minRSI)).Mul(big.NewDecimal(100))
37+
}
38+
39+
type rsiKIndicator struct {
40+
stochasticRSI Indicator
41+
window int
42+
}
43+
44+
// NewFastStochasticRSIIndicator returns a derivative Indicator which returns the fast stochastic RSI indicator (%K)
45+
// for the given stochastic window.
46+
func NewFastStochasticRSIIndicator(stochasticRSI Indicator, timeframe int) Indicator {
47+
return rsiKIndicator{stochasticRSI, timeframe}
48+
}
49+
50+
func (k rsiKIndicator) Calculate(index int) big.Decimal {
51+
return NewSimpleMovingAverage(k.stochasticRSI, k.window).Calculate(index)
52+
}
53+
54+
type rsiDIndicator struct {
55+
k Indicator
56+
window int
57+
}
58+
59+
// NewSlowStochasticRSIIndicator returns a derivative Indicator which returns the slow stochastic RSI indicator (%D)
60+
// for the given stochastic window.
61+
func NewSlowStochasticRSIIndicator(k Indicator, timeframe int) Indicator {
62+
return rsiDIndicator{k, timeframe}
63+
}
64+
65+
func (d rsiDIndicator) Calculate(index int) big.Decimal {
66+
return NewSimpleMovingAverage(d.k, d.window).Calculate(index)
67+
}

indicator_stochastic_rsi_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package techan
2+
3+
import (
4+
"math"
5+
"testing"
6+
7+
"github.com/sdcoffey/big"
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestStochasticRSIIndicator(t *testing.T) {
12+
indicator := NewStochasticRSIIndicator(NewClosePriceIndicator(mockedTimeSeries), 5)
13+
14+
expectedValues := []float64{
15+
math.Inf(1),
16+
math.Inf(1),
17+
math.Inf(1),
18+
math.Inf(1),
19+
math.Inf(1),
20+
math.Inf(1),
21+
100,
22+
95.9481,
23+
54.5245,
24+
93.1791,
25+
0,
26+
21.6754,
27+
}
28+
29+
indicatorEquals(t, expectedValues, indicator)
30+
}
31+
32+
func TestFastStochasticRSIIndicator(t *testing.T) {
33+
indicator := NewFastStochasticRSIIndicator(NewStochasticRSIIndicator(NewClosePriceIndicator(mockedTimeSeries),
34+
5), 3)
35+
36+
expectedValues := []float64{
37+
0,
38+
0,
39+
math.Inf(1),
40+
math.Inf(1),
41+
math.Inf(1),
42+
math.Inf(1),
43+
math.Inf(1),
44+
math.Inf(1),
45+
83.4909,
46+
81.2173,
47+
49.2346,
48+
38.2848,
49+
}
50+
51+
indicatorEquals(t, expectedValues, indicator)
52+
}
53+
54+
func TestSlowStochasticRSIIndicator(t *testing.T) {
55+
indicator := NewSlowStochasticRSIIndicator(NewFastStochasticRSIIndicator(NewStochasticRSIIndicator(
56+
NewClosePriceIndicator(mockedTimeSeries), 5), 3), 3)
57+
58+
expectedValues := []float64{
59+
0,
60+
0,
61+
math.Inf(1),
62+
math.Inf(1),
63+
math.Inf(1),
64+
math.Inf(1),
65+
math.Inf(1),
66+
math.Inf(1),
67+
math.Inf(1),
68+
math.Inf(1),
69+
71.3142,
70+
56.2456,
71+
}
72+
73+
indicatorEquals(t, expectedValues, indicator)
74+
}
75+
76+
func TestFastStochasticRSIIndicatorNoPriceChange(t *testing.T) {
77+
close := NewClosePriceIndicator(mockTimeSeries("42.0", "42.0"))
78+
rsInd := NewRelativeStrengthIndicator(close, 2)
79+
assert.Equal(t, big.NewDecimal(math.Inf(1)).FormattedString(2), rsInd.Calculate(1).FormattedString(2))
80+
}

0 commit comments

Comments
 (0)