Skip to content

Commit

Permalink
Implement Stochastic RSI Indicator
Browse files Browse the repository at this point in the history
  • Loading branch information
tsubus committed Apr 7, 2021
1 parent a2f4ef8 commit 8d5dab6
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 0 deletions.
65 changes: 65 additions & 0 deletions indicator_stochastic_rsi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package techan

import (
"github.com/sdcoffey/big"
)

type stochasticRSIIndicator struct {
curRSI Indicator
minRSI Indicator
maxRSI Indicator
}

// NewStochasticRSIIndicator returns a derivative Indicator which returns the stochastic RSI indicator for the given
// RSI window.
// https://www.investopedia.com/terms/s/stochrsi.asp
func NewStochasticRSIIndicator(indicator Indicator, timeframe int) Indicator {
rsiIndicator := NewRelativeStrengthIndexIndicator(indicator, timeframe)
return stochasticRSIIndicator{
curRSI: rsiIndicator,
minRSI: NewMinimumValueIndicator(rsiIndicator, timeframe),
maxRSI: NewMaximumValueIndicator(rsiIndicator, timeframe),
}
}

func (sri stochasticRSIIndicator) Calculate(index int) big.Decimal {
curRSI := sri.curRSI.Calculate(index)
minRSI := sri.minRSI.Calculate(index)
maxRSI := sri.maxRSI.Calculate(index)

if minRSI.EQ(maxRSI) {
return big.NewDecimal(100)
}

return curRSI.Sub(minRSI).Div(maxRSI.Sub(minRSI)).Mul(big.NewDecimal(100))
}

type stochRSIKIndicator struct {
stochasticRSI Indicator
window int
}

// NewFastStochasticRSIIndicator returns a derivative Indicator which returns the fast stochastic RSI indicator (%K)
// for the given stochastic window.
func NewFastStochasticRSIIndicator(stochasticRSI Indicator, timeframe int) Indicator {
return stochRSIKIndicator{stochasticRSI, timeframe}
}

func (k stochRSIKIndicator) Calculate(index int) big.Decimal {
return NewSimpleMovingAverage(k.stochasticRSI, k.window).Calculate(index)
}

type stochRSIDIndicator struct {
fastStochasticRSI Indicator
window int
}

// NewSlowStochasticRSIIndicator returns a derivative Indicator which returns the slow stochastic RSI indicator (%D)
// for the given stochastic window.
func NewSlowStochasticRSIIndicator(fastStochasticRSI Indicator, timeframe int) Indicator {
return stochRSIDIndicator{fastStochasticRSI, timeframe}
}

func (d stochRSIDIndicator) Calculate(index int) big.Decimal {
return NewSimpleMovingAverage(d.fastStochasticRSI, d.window).Calculate(index)
}
79 changes: 79 additions & 0 deletions indicator_stochastic_rsi_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package techan

import (
"testing"

"github.com/sdcoffey/big"
"github.com/stretchr/testify/assert"
)

func TestStochasticRSIIndicator(t *testing.T) {
indicator := NewStochasticRSIIndicator(NewClosePriceIndicator(mockedTimeSeries), 5)

expectedValues := []float64{
100,
100,
100,
100,
100,
100,
100,
95.9481,
54.5245,
93.1791,
0,
21.6754,
}

indicatorEquals(t, expectedValues, indicator)
}

func TestFastStochasticRSIIndicator(t *testing.T) {
indicator := NewFastStochasticRSIIndicator(NewStochasticRSIIndicator(NewClosePriceIndicator(mockedTimeSeries),
5), 3)

expectedValues := []float64{
0,
0,
100,
100,
100,
100,
100,
98.6494,
83.4909,
81.2173,
49.2346,
38.2848,
}

indicatorEquals(t, expectedValues, indicator)
}

func TestSlowStochasticRSIIndicator(t *testing.T) {
indicator := NewSlowStochasticRSIIndicator(NewFastStochasticRSIIndicator(NewStochasticRSIIndicator(
NewClosePriceIndicator(mockedTimeSeries), 5), 3), 3)

expectedValues := []float64{
0,
0,
33.3333,
66.6667,
100,
100,
100,
99.5498,
94.0468,
87.7858,
71.3142,
56.2456,
}

indicatorEquals(t, expectedValues, indicator)
}

func TestFastStochasticRSIIndicatorNoPriceChange(t *testing.T) {
close := NewClosePriceIndicator(mockTimeSeries("42.0", "42.0"))
rsInd := NewStochasticRSIIndicator(close, 2)
assert.Equal(t, big.NewDecimal(100).FormattedString(2), rsInd.Calculate(1).FormattedString(2))
}

0 comments on commit 8d5dab6

Please sign in to comment.