diff --git a/README.md b/README.md index 3328408..3adc0ed 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,7 @@ Thanks for trying **Pandas TA**! _Thank you for your contributions!_ -[alexonab](https://github.com/alexonab) | [allahyarzadeh](https://github.com/allahyarzadeh) | [codesutras](https://github.com/codesutras) | [daikts](https://github.com/daikts) | [DrPaprikaa](https://github.com/DrPaprikaa) | [FGU1](https://github.com/FGU1) | [lluissalord](https://github.com/lluissalord) | [maxdignan](https://github.com/maxdignan) | [NkosenhleDuma](https://github.com/NkosenhleDuma) | [pbrumblay](https://github.com/pbrumblay) | [RajeshDhalange](https://github.com/RajeshDhalange) | [rluong003](https://github.com/rluong003) | [SoftDevDanial](https://github.com/SoftDevDanial) | [tg12](https://github.com/tg12) | [twrobel](https://github.com/twrobel) | [YuvalWein](https://github.com/YuvalWein) +[alexonab](https://github.com/alexonab) | [allahyarzadeh](https://github.com/allahyarzadeh) | [codesutras](https://github.com/codesutras) | [daikts](https://github.com/daikts) | [DrPaprikaa](https://github.com/DrPaprikaa) | [FGU1](https://github.com/FGU1) | [lluissalord](https://github.com/lluissalord) | [maxdignan](https://github.com/maxdignan) | [NkosenhleDuma](https://github.com/NkosenhleDuma) | [pbrumblay](https://github.com/pbrumblay) | [RajeshDhalange](https://github.com/RajeshDhalange) | [rengel8](https://github.com/rengel8) | [rluong003](https://github.com/rluong003) | [SoftDevDanial](https://github.com/SoftDevDanial) | [tg12](https://github.com/tg12) | [twrobel](https://github.com/twrobel) | [YuvalWein](https://github.com/YuvalWein)
@@ -426,7 +426,7 @@ print(bothhl2.name) # "pre_HL2_post" * _Inside Bar_: **cdl_inside** * _Heikin-Ashi_: **ha** -### **Momentum** (35) +### **Momentum** (36) * _Awesome Oscillator_: **ao** * _Absolute Price Oscillator_: **apo** @@ -453,6 +453,7 @@ print(bothhl2.name) # "pre_HL2_post" * _Quantitative Qualitative Estimation_: **qqe** * _Rate of Change_: **roc** * _Relative Strength Index_: **rsi** +* _Relative Strength Xtra_: **rsx** * _Relative Vigor Index_: **rvgi** * _Slope_: **slope** * _SMI Ergodic_ **smi** @@ -652,16 +653,17 @@ result = ta.cagr(df.close) ## **New Indicators** -* _Drawdown_ (**drawdown**) It is a peak-to-trough decline during a specific period for an investment, +* _Drawdown_ (**drawdown**) shows the peak-to-trough decline during a specific period for an investment, trading account, or fund. See: ```help(ta.drawdown)``` -* _Gann High-Low Activator_ (**hilo**) The Gann High Low Activator Indicator was created by Robert Krausz in a 1998. See: ```help(ta.hilo)``` -* _Quantitative Qualitative Estimation_ (**qqe**) The Quantitative Qualitative Estimation (QQE) is like SuperTrend for a Smoothed RSI. See: ```help(ta.qqe)``` -* _Price Volume Rank_ (**pvr**) Price Volume Rank (PVR) was created by Anthony J. Macek and is described in his +* _Gann High-Low Activator_ (**hilo**) was created by Robert Krausz in a 1998. See: ```help(ta.hilo)``` +* _Quantitative Qualitative Estimation_ (**qqe**) is like SuperTrend for a Smoothed RSI. See: ```help(ta.qqe)``` +* _Price Volume Rank_ (**pvr**) was created by Anthony J. Macek and is described in his article in the June, 1994 issue of Technical Analysis of Stocks & Commodities Magazine. See: ```help(ta.pvr)``` +* _Relative Strength Xtra_ (**rsx**) is based on the popular RSI indicator and inspired by the work Jurik Research. See: ```help(ta.rsx)``` * _Ehler's Super Smoother Filter_ (**ssf**). Ehler's solution to reduce lag and remove aliasing noise compared to other common moving average indicators. See: ```help(ta.ssf)``` -* _Elder's Thermometer_ (**thermo**) Elder's Thermometer measures price volatility. See: ```help(ta.thermo)``` -* _TTM Trend_ (**ttm_trend**). A trend indicator inspired from John Carter's book "Mastering the Trade" issue of Stocks & Commodities Magazine. It is a moving average based trend indicator consisting of two different simple moving averages. See: ```help(ta.ttm_trend)``` -* _Variable Index Dynamic Average_ (**vidya**) A popular Dynamic Moving Average created by Tushar Chande. See: ```help(ta.vidya)``` +* _Elder's Thermometer_ (**thermo**) measures price volatility. See: ```help(ta.thermo)``` +* _TTM Trend_ (**ttm_trend**) is a trend indicator inspired from John Carter's book "Mastering the Trade" issue of Stocks & Commodities Magazine. It is a moving average based trend indicator consisting of two different simple moving averages. See: ```help(ta.ttm_trend)``` +* _Variable Index Dynamic Average_ (**vidya**) is a popular Dynamic Moving Average created by Tushar Chande. See: ```help(ta.vidya)``` ## **Updated Indicators** * _Average True Range_ (**atr**): The default ```mamode``` is now "**RMA**" and with the same ```mamode``` options as TradingView. See ```help(ta.atr)```. diff --git a/pandas_ta/__init__.py b/pandas_ta/__init__.py index 395778b..a4cee55 100644 --- a/pandas_ta/__init__.py +++ b/pandas_ta/__init__.py @@ -43,8 +43,9 @@ Category = { "momentum": [ "ao", "apo", "bias", "bop", "brar", "cci", "cfo", "cg", "cmo", "coppock", "er", "eri", "fisher", "inertia", "kdj", "kst", "macd", - "mom", "pgo", "ppo", "psl", "pvo", "qqe", "roc", "rsi", "rsx", "rvgi", "slope", - "smi", "squeeze", "stoch", "stochrsi", "trix", "tsi", "uo", "willr" + "mom", "pgo", "ppo", "psl", "pvo", "qqe", "roc", "rsi", "rsx", "rvgi", + "slope", "smi", "squeeze", "stoch", "stochrsi", "trix", "tsi", "uo", + "willr" ], # Overlap "overlap": [ diff --git a/pandas_ta/core.py b/pandas_ta/core.py index f2bf88d..c585b57 100644 --- a/pandas_ta/core.py +++ b/pandas_ta/core.py @@ -880,7 +880,7 @@ class AnalysisIndicators(BasePandasObject): close = self._get_column(kwargs.pop("close", "close")) result = rsi(close=close, length=length, scalar=scalar, drift=drift, offset=offset, **kwargs) return self._post_process(result, **kwargs) - + def rsx(self, length=None, drift=None, offset=None, **kwargs): close = self._get_column(kwargs.pop("close", "close")) result = rsx(close=close, length=length, drift=drift, offset=offset, **kwargs) diff --git a/pandas_ta/momentum/rsx.py b/pandas_ta/momentum/rsx.py index 9542024..facfdc7 100644 --- a/pandas_ta/momentum/rsx.py +++ b/pandas_ta/momentum/rsx.py @@ -2,7 +2,7 @@ from numpy import NaN as npNaN from pandas import DataFrame, Series, concat from pandas_ta.utils import get_drift, get_offset, verify_series, signals - + def rsx(close, length=None, drift=None, offset=None, **kwargs): """Indicator: Relative Strength Xtra (inspired by Jurik RSX)""" # Validate arguments @@ -10,38 +10,15 @@ def rsx(close, length=None, drift=None, offset=None, **kwargs): length = int(length) if length and length > 0 else 14 drift = get_drift(drift) offset = get_offset(offset) - + # variables - f0 = 0 - f8 = 0 - f10 = 0 - f18 = 0 - f20 = 0 - f28 = 0 - f30 = 0 - f38 = 0 - f40 = 0 - f48 = 0 - f50 = 0 - f58 = 0 - f60 = 0 - f68 = 0 - f70 = 0 - f78 = 0 - f80 = 0 - f88 = 0 - f90 = 0 + vC, v1C = 0, 0 + v4, v8, v10, v14, v18, v20 = 0, 0, 0, 0, 0, 0 - v4 = 0 - v8 = 0 - v10 = 0 - v14 = 0 - v18 = 0 - v20 = 0 + f0, f8, f10, f18, f20, f28, f30, f38 = 0, 0, 0, 0, 0, 0, 0, 0 + f40, f48, f50, f58, f60, f68, f70, f78 = 0, 0, 0, 0, 0, 0, 0, 0 + f80, f88, f90 = 0, 0, 0 - vC = 0 - v1C = 0 - # Calculate Result m = close.size result = [npNaN for _ in range(0, length - 1)] + [0] @@ -66,26 +43,28 @@ def rsx(close, length=None, drift=None, offset=None, **kwargs): v8 = f8 - f10 f28 = f20 * f28 + f18 * v8 f30 = f18 * f28 + f20 * f30 - vC = f28 * 1.5 - f30 * 0.5 + vC = 1.5 * f28 - 0.5 * f30 f38 = f20 * f38 + f18 * vC f40 = f18 * f38 + f20 * f40 - v10 = f38 * 1.5 - f40 * 0.5 + v10 = 1.5 * f38 - 0.5 * f40 f48 = f20 * f48 + f18 * v10 f50 = f18 * f48 + f20 * f50 - v14 = f48 * 1.5 - f50 * 0.5 + v14 = 1.5 * f48 - 0.5 * f50 f58 = f20 * f58 + f18 * abs(v8) f60 = f18 * f58 + f20 * f60 - v18 = f58 * 1.5 - f60 * 0.5 + v18 = 1.5 * f58 - 0.5 * f60 f68 = f20 * f68 + f18 * v18 f70 = f18 * f68 + f20 * f70 - v1C = f68 * 1.5 - f70 * 0.5 + v1C = 1.5 * f68 - 0.5 * f70 f78 = f20 * f78 + f18 * v1C f80 = f18 * f78 + f20 * f80 - v20 = f78 * 1.5 - f80 * 0.5 + v20 = 1.5 * f78 - 0.5 * f80 + if f88 >= f90 and f8 != f10: f0 = 1.0 if f88 == f90 and f0 == 0.0: f90 = 0.0 + if f88 < f90 and v20 > 0.0000000001: v4 = (v14 / v20 + 1.0) * 50.0 if v4 > 100.0: @@ -95,7 +74,6 @@ def rsx(close, length=None, drift=None, offset=None, **kwargs): else: v4 = 50.0 result.append(v4) - # print('v4', v4) rsx = Series(result, index=close.index) # Offset @@ -109,8 +87,6 @@ def rsx(close, length=None, drift=None, offset=None, **kwargs): rsx.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it - # print(rsx) - # print(length) rsx.name = f"RSX_{length}" rsx.category = "momentum" @@ -142,9 +118,11 @@ def rsx(close, length=None, drift=None, offset=None, **kwargs): rsx.__doc__ = \ """Relative Strength Xtra (rsx) -The Relative Strength Xtra is based on the popular RSI indicator and inspired by the work Jurik Research. -The code implemented is based on published code found at 'prorealcode.com'. This enhanced version of the rsi -reduces noise and provides a clearer, only slightly delayed insight on momentum and velocity of price movements. +The Relative Strength Xtra is based on the popular RSI indicator and inspired +by the work Jurik Research. The code implemented is based on published code +found at 'prorealcode.com'. This enhanced version of the rsi reduces noise and +provides a clearer, only slightly delayed insight on momentum and velocity of +price movements. Sources: http://www.jurikres.com/catalog1/ms_rsx.htm @@ -152,12 +130,12 @@ Sources: Calculation: Refer to the sources above for information as well as code example. - + Args: close (pd.Series): Series of 'close's - length (int): It's period. Default: 14 - drift (int): The difference period. Default: 1 - offset (int): How many periods to offset the result. Default: 0 + length (int): It's period. Default: 14 + drift (int): The difference period. Default: 1 + offset (int): How many periods to offset the result. Default: 0 Kwargs: fillna (value, optional): pd.DataFrame.fillna(value) diff --git a/setup.py b/setup.py index ebd0228..f4869c9 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ setup( "pandas_ta.volatility", "pandas_ta.volume" ], - version=".".join(("0", "2", "34b")), + version=".".join(("0", "2", "35b")), description=long_description, long_description=long_description, author="Kevin Johnson", diff --git a/tests/test_ext_indicator_momentum.py b/tests/test_ext_indicator_momentum.py index 271148c..c4d6900 100644 --- a/tests/test_ext_indicator_momentum.py +++ b/tests/test_ext_indicator_momentum.py @@ -153,6 +153,11 @@ class TestMomentumExtension(TestCase): self.assertIsInstance(self.data, DataFrame) self.assertEqual(self.data.columns[-1], "RSI_14") + def test_rsx_ext(self): + self.data.ta.rsx(append=True) + self.assertIsInstance(self.data, DataFrame) + self.assertEqual(self.data.columns[-1], "RSX_14") + def test_rvgi_ext(self): self.data.ta.rvgi(append=True) self.assertIsInstance(self.data, DataFrame) diff --git a/tests/test_indicator_momentum.py b/tests/test_indicator_momentum.py index 2e09f5e..5aa9a84 100644 --- a/tests/test_indicator_momentum.py +++ b/tests/test_indicator_momentum.py @@ -295,6 +295,11 @@ class TestMomentum(TestCase): except Exception as ex: error_analysis(result, CORRELATION, ex) + def test_rsx(self): + result = pandas_ta.rsx(self.close) + self.assertIsInstance(result, Series) + self.assertEqual(result.name, "RSX_14") + def test_rvgi(self): result = pandas_ta.rvgi(self.open, self.high, self.low, self.close) self.assertIsInstance(result, DataFrame)