Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature 146 use any smoother for sobv #147

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions talipp/indicators/IndicatorFactory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from talipp.indicators.Smoother import Smoother
from talipp.ma import MAType


class IndicatorFactory:
"""Indicator factory."""

@staticmethod
def get_smoother(indicator_class, ma_type: MAType = MAType.SMA):
"""
Return a smoother ie an indicator which can smoothed input values using a moving average

Args:
indicator_class: indicator class
ma_type: Moving average type.
"""
return Smoother(indicator_class, ma_type)
58 changes: 15 additions & 43 deletions talipp/indicators/SOBV.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,16 @@
from typing import List, Any

from talipp.indicator_util import has_valid_values
from talipp.indicators.Indicator import Indicator, InputModifierType
from talipp.indicators.OBV import OBV
from talipp.input import SamplingPeriodType
from talipp.ohlcv import OHLCV


class SOBV(Indicator):
"""Smoothed On Balance Volume.

Input type: [OHLCV][talipp.ohlcv.OHLCV]

Output type: `float`

Args:
period: Moving average period.
input_values: List of input values.
input_indicator: Input indicator.
input_modifier: Input modifier.
input_sampling: Input sampling type.
"""

def __init__(self, period: int,
input_values: List[OHLCV] = None,
input_indicator: Indicator = None,
input_modifier: InputModifierType = None,
input_sampling: SamplingPeriodType = None):
super().__init__(input_modifier=input_modifier,
input_sampling=input_sampling)

self.period = period

self.obv = OBV()
self.add_sub_indicator(self.obv)

self.initialize(input_values, input_indicator)

def _calculate_new_value(self) -> Any:
if not has_valid_values(self.obv, self.period):
return None

return sum(self.obv[-self.period:]) / float(self.period)
from talipp.indicators.IndicatorFactory import IndicatorFactory
from talipp.ma import MAType


"""Smoothed On Balance Volume.
Input type: [OHLCV][talipp.ohlcv.OHLCV]
Output type: `float`
Args:
period: Moving average period.
input_values: List of input values.
input_indicator: Input indicator.
input_modifier: Input modifier.
input_sampling: Input sampling type.
"""
SOBV = IndicatorFactory.get_smoother(OBV, MAType.SMA)
32 changes: 32 additions & 0 deletions talipp/indicators/Smoother.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from typing import Any
from talipp.indicators.Indicator import Indicator
from talipp.ma import MAFactory, MAType


class Smoother(Indicator):
def __init__(self, indicator_class, ma_type: MAType):
super().__init__()

self.indicator_class = indicator_class
self.ma_type = ma_type

def __call__(
self,
smoothing_period: int,
input_values=None,
input_indicator=None,
*args: Any,
**kwargs
) -> Any:
self.ma = MAFactory.get_ma(self.ma_type, smoothing_period)

self.internal_indicator = self.indicator_class(*args, **kwargs)
self.add_sub_indicator(self.internal_indicator)

self.initialize(input_values, input_indicator)

return self

def _calculate_new_value(self) -> Any:
self.ma.add(self.internal_indicator.output_values)
return self.ma.output_values[-1]
6 changes: 3 additions & 3 deletions test/TalippTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def assertIndicatorUpdate(self, indicator: Indicator, iterations_no: int = 20):

indicator.update(last_input_value)

self.assertEqual(last_indicator_value, indicator[-1])
self.assertAlmostEqual(last_indicator_value, indicator[-1], places = 5)

def assertIndicatorDelete(self, indicator: Indicator, iterations_no: int = 20):
last_indicator_value = indicator[-1]
Expand All @@ -48,13 +48,13 @@ def assertIndicatorDelete(self, indicator: Indicator, iterations_no: int = 20):
indicator.remove()

# verify that adding and then removing X input values returns the original output value
self.assertEqual(last_indicator_value, indicator[-1])
self.assertAlmostEqual(last_indicator_value, indicator[-1], places = 5)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about that


# delete the original last input value and add it back and check the original last output value is returned
indicator.remove()
indicator.add(last_input_value)

self.assertEqual(last_indicator_value, indicator[-1])
self.assertAlmostEqual(last_indicator_value, indicator[-1], places = 5)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here


def assertIndicatorPurgeOldest(self, indicator: Indicator):
# purge oldest 5 values
Expand Down
12 changes: 5 additions & 7 deletions test/test_SOBV.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,11 @@ def setUp(self) -> None:
self.input_values = list(TalippTest.OHLCV_TMPL)

def test_init(self):
ind = SOBV(20, self.input_values)
ind = SOBV(20, input_values=self.input_values)

print(ind)

self.assertAlmostEqual(ind[-3], 90.868499, places = 5)
self.assertAlmostEqual(ind[-2], 139.166499, places = 5)
self.assertAlmostEqual(ind[-1], 187.558499, places = 5)
self.assertAlmostEqual(ind[-3], 90.868499, places=5)
self.assertAlmostEqual(ind[-2], 139.166499, places=5)
self.assertAlmostEqual(ind[-1], 187.558499, places=5)

def test_update(self):
self.assertIndicatorUpdate(SOBV(20, self.input_values))
Expand All @@ -28,5 +26,5 @@ def test_purge_oldest(self):
self.assertIndicatorPurgeOldest(SOBV(20, self.input_values))


if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()
Loading