-
Notifications
You must be signed in to change notification settings - Fork 147
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #35 from tsubus/stochastic
Implement Stochastic Oscillator Indicator
- Loading branch information
Showing
4 changed files
with
141 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,4 +5,4 @@ go 1.12 | |
require ( | ||
github.com/sdcoffey/big v0.7.0 | ||
github.com/stretchr/testify v1.7.0 | ||
) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package techan | ||
|
||
import ( | ||
"math" | ||
|
||
"github.com/sdcoffey/big" | ||
) | ||
|
||
type kIndicator struct { | ||
closePrice Indicator | ||
minValue Indicator | ||
maxValue Indicator | ||
window int | ||
} | ||
|
||
// NewFastStochasticIndicator returns a derivative Indicator which returns the fast stochastic indicator (%K) for the | ||
// given window. | ||
// https://www.investopedia.com/terms/s/stochasticoscillator.asp | ||
func NewFastStochasticIndicator(series *TimeSeries, timeframe int) Indicator { | ||
return kIndicator{ | ||
closePrice: NewClosePriceIndicator(series), | ||
minValue: NewMinimumValueIndicator(NewLowPriceIndicator(series), timeframe), | ||
maxValue: NewMaximumValueIndicator(NewHighPriceIndicator(series), timeframe), | ||
window: timeframe, | ||
} | ||
} | ||
|
||
func (k kIndicator) Calculate(index int) big.Decimal { | ||
closeVal := k.closePrice.Calculate(index) | ||
minVal := k.minValue.Calculate(index) | ||
maxVal := k.maxValue.Calculate(index) | ||
|
||
if minVal.EQ(maxVal) { | ||
return big.NewDecimal(math.Inf(1)) | ||
} | ||
|
||
return closeVal.Sub(minVal).Div(maxVal.Sub(minVal)).Mul(big.NewDecimal(100)) | ||
} | ||
|
||
type dIndicator struct { | ||
k Indicator | ||
window int | ||
} | ||
|
||
// NewSlowStochasticIndicator returns a derivative Indicator which returns the slow stochastic indicator (%D) for the | ||
// given window. | ||
// https://www.investopedia.com/terms/s/stochasticoscillator.asp | ||
func NewSlowStochasticIndicator(k Indicator, window int) Indicator { | ||
return dIndicator{k, window} | ||
} | ||
|
||
func (d dIndicator) Calculate(index int) big.Decimal { | ||
return NewSimpleMovingAverage(d.k, d.window).Calculate(index) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package techan | ||
|
||
import ( | ||
"math" | ||
"testing" | ||
|
||
"github.com/sdcoffey/big" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
var fastStochValues = []float64{ | ||
100, | ||
100, | ||
100.0 * 12.0 / 16.0, | ||
100.0 * 2.0 / 16.0, | ||
100.0 * 6.0 / 16.0, | ||
100.0 * 2.0 / 16.0, | ||
100.0 * 3.0 / 15.0, | ||
100.0 * 2.0 / 16.0, | ||
100.0 * 4.0 / 13.0, | ||
100.0 * 11.0 / 17.0, | ||
100.0 * 24.0 / 49.0, | ||
} | ||
|
||
func TestFastStochasticIndicator(t *testing.T) { | ||
ts := mockTimeSeriesOCHL( | ||
[]float64{10, 12, 12, 8}, | ||
[]float64{11, 14, 14, 9}, | ||
[]float64{10, 20, 24, 10}, | ||
[]float64{9, 10, 11, 9}, | ||
[]float64{11, 14, 14, 9}, | ||
[]float64{9, 10, 11, 9}, | ||
[]float64{10, 12, 12, 10}, | ||
[]float64{9, 10, 11, 8}, | ||
[]float64{6, 5, 8, 1}, | ||
[]float64{15, 12, 18, 9}, | ||
[]float64{35, 25, 50, 20}, | ||
) | ||
|
||
window := 6 | ||
|
||
k := NewFastStochasticIndicator(ts, window) | ||
|
||
decimalEquals(t, fastStochValues[0], k.Calculate(0)) | ||
decimalEquals(t, fastStochValues[1], k.Calculate(1)) | ||
decimalEquals(t, fastStochValues[2], k.Calculate(2)) | ||
decimalEquals(t, fastStochValues[3], k.Calculate(3)) | ||
decimalEquals(t, fastStochValues[4], k.Calculate(4)) | ||
decimalEquals(t, fastStochValues[5], k.Calculate(5)) | ||
decimalEquals(t, fastStochValues[6], k.Calculate(6)) | ||
decimalEquals(t, fastStochValues[7], k.Calculate(7)) | ||
decimalEquals(t, fastStochValues[8], k.Calculate(8)) | ||
decimalEquals(t, fastStochValues[9], k.Calculate(9)) | ||
decimalEquals(t, fastStochValues[10], k.Calculate(10)) | ||
} | ||
|
||
func TestSlowStochasticIndicator(t *testing.T) { | ||
ts := mockTimeSeriesFl(fastStochValues...) | ||
|
||
window := 3 | ||
|
||
d := NewSlowStochasticIndicator(NewClosePriceIndicator(ts), window) | ||
|
||
decimalEquals(t, 0, d.Calculate(0)) | ||
decimalEquals(t, 0, d.Calculate(1)) | ||
decimalEquals(t, 100.0*(12.0/16.0+1+1)/3.0, d.Calculate(2)) | ||
decimalEquals(t, 100.0*(2.0/16.0+12.0/16.0+1)/3.0, d.Calculate(3)) | ||
decimalEquals(t, 100.0*(6.0/16.0+2.0/16.0+12.0/16.0)/3.0, d.Calculate(4)) | ||
decimalEquals(t, 100.0*(2.0/16.0+6.0/16.0+2.0/16.0)/3.0, d.Calculate(5)) | ||
decimalEquals(t, 100.0*(3.0/15.0+2.0/16.0+6.0/16.0)/3.0, d.Calculate(6)) | ||
decimalEquals(t, 100.0*(2.0/16.0+3.0/15.0+2.0/16.0)/3.0, d.Calculate(7)) | ||
decimalEquals(t, 100.0*(4.0/13.0+2.0/16.0+3.0/15.0)/3.0, d.Calculate(8)) | ||
decimalEquals(t, 100.0*(11.0/17.0+4.0/13.0+2.0/16.0)/3.0, d.Calculate(9)) | ||
decimalEquals(t, 100.0*(24.0/49.0+11.0/17.0+4.0/13.0)/3.0, d.Calculate(10)) | ||
} | ||
|
||
func TestFastStochasticIndicatorNoPriceChange(t *testing.T) { | ||
ts := mockTimeSeriesOCHL( | ||
[]float64{42, 42, 42, 42}, | ||
[]float64{42, 42, 42, 42}, | ||
) | ||
|
||
k := NewFastStochasticIndicator(ts, 2) | ||
assert.Equal(t, big.NewDecimal(math.Inf(1)).FormattedString(2), k.Calculate(1).FormattedString(2)) | ||
} |