Skip to content

Commit

Permalink
feat: Add optional params on Stochastic Oscillator (#372)
Browse files Browse the repository at this point in the history
  • Loading branch information
LeeDongGeon1996 authored Apr 14, 2024
1 parent ad9030c commit 16665c8
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 3 deletions.
17 changes: 15 additions & 2 deletions stock_indicators/indicators/stoch.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

from stock_indicators._cslib import CsIndicator
from stock_indicators._cstypes import List as CsList
from stock_indicators.indicators.common.enums import MAType
from stock_indicators.indicators.common.helpers import RemoveWarmupMixin
from stock_indicators.indicators.common.results import IndicatorResults, ResultBase
from stock_indicators.indicators.common.quote import Quote


def get_stoch(quotes: Iterable[Quote], lookback_periods: int = 14, signal_periods: int = 3, smooth_periods: int = 3):
def get_stoch(quotes: Iterable[Quote], lookback_periods: int = 14, signal_periods: int = 3, smooth_periods: int = 3,
k_factor: float = 3, d_factor: float = 2, ma_type: MAType = MAType.SMA):
"""Get Stochastic Oscillator calculated, with KDJ indexes.
Stochastic Oscillatoris a momentum indicator that looks back N periods to produce a scale of 0 to 100.
Expand All @@ -27,6 +29,16 @@ def get_stoch(quotes: Iterable[Quote], lookback_periods: int = 14, signal_period
Smoothing period for the %K Oscillator.
Use 3 for Slow or 1 for Fast.
`k_factor` : float, defaults 3
Weight of %K in the %J calculation.
`d_factor` : float, defaults 2
Weight of %K in the %J calculation.
`ma_type` : MAType, defaults MAType.SMA
Type of moving average to use.
See docs for instructions and options.
Returns:
`StochResults[StochResult]`
StochResults is list of StochResult with providing useful helper methods.
Expand All @@ -35,7 +47,8 @@ def get_stoch(quotes: Iterable[Quote], lookback_periods: int = 14, signal_period
- [Stochastic Oscillator Reference](https://python.stockindicators.dev/indicators/Stoch/#content)
- [Helper Methods](https://python.stockindicators.dev/utilities/#content)
"""
stoch_results = CsIndicator.GetStoch[Quote](CsList(Quote, quotes), lookback_periods, signal_periods, smooth_periods)
stoch_results = CsIndicator.GetStoch[Quote](CsList(Quote, quotes), lookback_periods, signal_periods, smooth_periods,
k_factor, d_factor, ma_type.cs_value)
return StochResults(stoch_results, StochResult)


Expand Down
53 changes: 52 additions & 1 deletion tests/test_stoch.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pytest
from stock_indicators import indicators
from stock_indicators.indicators.common.enums import MAType

class TestStoch:
def test_standard(self, quotes):
Expand Down Expand Up @@ -34,6 +35,43 @@ def test_standard(self, quotes):
assert 35.5674 == round(float(r.signal), 4)
assert 58.2712 == round(float(r.percent_j), 4)

def test_extended(self, quotes):
results = indicators.get_stoch(quotes, 9, 3, 3, 5, 4, MAType.SMMA)

assert 502 == len(results)
assert 494 == len(list(filter(lambda x: x.k is not None, results)))
assert 494 == len(list(filter(lambda x: x.d is not None, results)))

r = results[7]
assert r.k is None
assert r.d is None
assert r.j is None

r = results[8]
assert 81.9178 == round(float(r.k), 4)
assert 81.9178 == round(float(r.d), 4)
assert 81.9178 == round(float(r.j), 4)

r = results[17]
assert 82.5181 == round(float(r.k), 4)
assert 76.2603 == round(float(r.d), 4)
assert 107.5491 == round(float(r.j), 4)

r = results[149]
assert 77.1571 == round(float(r.k), 4)
assert 72.8206 == round(float(r.d), 4)
assert 94.5030 == round(float(r.j), 4)

r = results[249]
assert 74.3652 == round(float(r.k), 4)
assert 75.5660 == round(float(r.d), 4)
assert 69.5621 == round(float(r.j), 4)

r = results[501]
assert 46.9807 == round(float(r.k), 4)
assert 32.0413 == round(float(r.d), 4)
assert 106.7382 == round(float(r.j), 4)

def test_no_signal(self, quotes):
results = indicators.get_stoch(quotes, 5, 1, 3)

Expand All @@ -56,7 +94,6 @@ def test_fast(self, quotes):
assert 91.6233 == round(float(r.oscillator), 4)
assert 36.0608 == round(float(r.signal), 4)


def test_fast_small(self, quotes):
results = indicators.get_stoch(quotes, 1, 10, 1)

Expand All @@ -70,6 +107,20 @@ def test_bad_data(self, bad_quotes):
r = indicators.get_stoch(bad_quotes, 15)
assert 502 == len(r)

def test_no_quotes(self, quotes):
r = indicators.get_stoch([])
assert 0 == len(r)

r = indicators.get_stoch(quotes[:1])
assert 1 == len(r)

def test_boundary(self, quotes):
results = indicators.get_stoch(quotes, 14, 3, 3)

assert 0 == len(list(filter(lambda x: x.k is not None and (x.k < 0 or x.k > 100), results)))
assert 0 == len(list(filter(lambda x: x.d is not None and (x.d < 0 or x.d > 100), results)))
assert 0 == len(list(filter(lambda x: x.j is not None and (x.d < 0 or x.d > 100), results)))

def test_removed(self, quotes):
results = indicators.get_stoch(quotes, 14, 3, 3).remove_warmup_periods()

Expand Down

0 comments on commit 16665c8

Please sign in to comment.