From 82d0d25bd2ba8c2d0e8f9e47a4e6143da94e1d29 Mon Sep 17 00:00:00 2001 From: Kevin Johnson Date: Wed, 24 Apr 2019 11:19:02 -0700 Subject: [PATCH] added long_run indicator and tests --- README.md | 3 ++- pandas_ta/core.py | 13 ++++++++++--- pandas_ta/trend.py | 30 ++++++++++++++++++++++++++++++ tests/test_indicator_trend.py | 5 +++++ tests/test_indicator_trend_ext.py | 10 ++++++++++ 5 files changed, 57 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index eb0f47b..7f03704 100644 --- a/README.md +++ b/README.md @@ -163,13 +163,14 @@ Use parameter: cumulative=**True** for cumulative results. |:--------:| | ![Example Z Score](/images/SPY_ZScore.png) | -## _Trend_ (7) +## _Trend_ (8) * _Average Directional Movement Index_: **adx** * _Aroon Oscillator_: **aroon** * _Decreasing_: **decreasing** * _Detrended Price Oscillator_: **dpo** * _Increasing_: **increasing** +* _Long Run_: **long_run** * _Q Stick_: **qstick** * _Vortex_: **vortex** diff --git a/pandas_ta/core.py b/pandas_ta/core.py index 04468e9..a9a806d 100644 --- a/pandas_ta/core.py +++ b/pandas_ta/core.py @@ -608,6 +608,15 @@ class AnalysisIndicators(BasePandasObject): self._append(result, **kwargs) return result + def long_run(self, fast=None, slow=None, length=None, offset=None, **kwargs): + if fast is None and slow is None: return self._df + else: + fast = self._get_column(fast, f"{fast}") + slow = self._get_column(slow, f"{slow}") + result = long_run(fast=fast, slow=slow, length=length, offset=offset, **kwargs) + self._append(result, **kwargs) + return result + def qstick(self, open_=None, close=None, length=None, offset=None, **kwargs): open_ = self._get_column(open_, 'open') close = self._get_column(close, 'close') @@ -627,9 +636,7 @@ class AnalysisIndicators(BasePandasObject): # Utility Indicators def cross(self, a=None, b=None, above=True, asint=True, offset=None, **kwargs): - if a is None and b is None: - print(f" [X] Series ") - return self._df + if a is None and b is None: return self._df else: a = self._get_column(a, f"{a}") b = self._get_column(b, f"{b}") diff --git a/pandas_ta/trend.py b/pandas_ta/trend.py index 1c6f31a..4d694ac 100644 --- a/pandas_ta/trend.py +++ b/pandas_ta/trend.py @@ -205,6 +205,36 @@ def increasing(close, length=None, asint=True, offset=None, **kwargs): return increasing +def long_run(fast, slow, length=None, offset=None, **kwargs): + """Indicator: Long Run""" + # Validate Arguments + fast = verify_series(fast) + slow = verify_series(slow) + length = int(length) if length and length > 0 else 2 + offset = get_offset(offset) + + # Calculate Result + pb = increasing(fast, length) & decreasing(slow, length) # potential bottom or bottom + bi = increasing(fast, length) & increasing(slow, length) # fast and slow are increasing + long_run = pb | bi + + # Offset + if offset != 0: + long_run = long_run.shift(offset) + + # Handle fills + if 'fillna' in kwargs: + long_run.fillna(kwargs['fillna'], inplace=True) + if 'fill_method' in kwargs: + long_run.fillna(method=kwargs['fill_method'], inplace=True) + + # Name and Categorize it + long_run.name = f"LR_{length}" + long_run.category = 'trend' + + return long_run + + def qstick(open_, close, length=None, offset=None, **kwargs): """Indicator: Q Stick""" # Validate Arguments diff --git a/tests/test_indicator_trend.py b/tests/test_indicator_trend.py index 86b299e..17d0208 100644 --- a/tests/test_indicator_trend.py +++ b/tests/test_indicator_trend.py @@ -89,6 +89,11 @@ class TestTrend(TestCase): self.assertIsInstance(result, Series) self.assertEqual(result.name, 'INC_1') + def test_long_run(self): + result = self.trend.long_run(self.close, self.open) + self.assertIsInstance(result, Series) + self.assertEqual(result.name, 'LR_2') + def test_qstick(self): result = self.trend.qstick(self.open, self.close) self.assertIsInstance(result, Series) diff --git a/tests/test_indicator_trend_ext.py b/tests/test_indicator_trend_ext.py index 1cbc25e..3053c00 100644 --- a/tests/test_indicator_trend_ext.py +++ b/tests/test_indicator_trend_ext.py @@ -48,6 +48,16 @@ class TestTrendExtension(TestCase): self.assertIsInstance(self.data, DataFrame) self.assertEqual(self.data.columns[-1], 'INC_1') + def test_long_run_ext(self): + # Nothing passed, return self + self.assertEqual(self.data.ta.long_run(append=True).shape, self.data.shape) + + fast = self.data.ta.ema('close', 8) + slow = self.data.ta.ema('close', 21) + self.data.ta.long_run(fast, slow, append=True) + self.assertIsInstance(self.data, DataFrame) + self.assertEqual(self.data.columns[-1], 'LR_2') + def test_qstick_ext(self): self.data.ta.qstick(append=True) self.assertIsInstance(self.data, DataFrame)