diff --git a/README.md b/README.md index d41a0e49..ae10fba2 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ It is a Technical Analysis library useful to do feature engineering from financi ![Bollinger Bands graph example](doc/figure.png) -The library has implemented 34 indicators: +The library has implemented 42 indicators: #### Volume @@ -31,9 +31,13 @@ The library has implemented 34 indicators: * Bollinger Bands (BB) * Keltner Channel (KC) * Donchian Channel (DC) +* Ulcer Index (UI) #### Trend +* Simple Moving Average (SMA) +* Exponential Moving Average (EMA) +* Weighted Moving Average (WMA) * Moving Average Convergence Divergence (MACD) * Average Directional Movement Index (ADX) * Vortex Indicator (VI) @@ -44,10 +48,12 @@ The library has implemented 34 indicators: * KST Oscillator (KST) * Ichimoku Kinkō Hyō (Ichimoku) * Parabolic Stop And Reverse (Parabolic SAR) +* Schaff Trend Cycle (STC) #### Momentum * Relative Strength Index (RSI) +* Stochastic RSI (SRSI) * True strength index (TSI) * Ultimate Oscillator (UO) * Stochastic Oscillator (SR) @@ -55,6 +61,8 @@ The library has implemented 34 indicators: * Awesome Oscillator (AO) * Kaufman's Adaptive Moving Average (KAMA) * Rate of Change (ROC) +* Percentage Price Oscillator (PPO) +* Percentage Volume Oscillator (PVO) #### Others diff --git a/ta/momentum.py b/ta/momentum.py index 95b0cd3f..baa8d138 100644 --- a/ta/momentum.py +++ b/ta/momentum.py @@ -8,7 +8,7 @@ import numpy as np import pandas as pd -from ta.utils import IndicatorMixin +from ta.utils import IndicatorMixin, ema class RSIIndicator(IndicatorMixin): @@ -461,6 +461,198 @@ def wr(self) -> pd.Series: return pd.Series(wr, name='wr') +class StochRSIIndicator(IndicatorMixin): + """Stochastic RSI + + The StochRSI oscillator was developed to take advantage of both momentum + indicators in order to create a more sensitive indicator that is attuned to + a specific security's historical performance rather than a generalized analysis + of price change. + + https://school.stockcharts.com/doku.php?id=technical_indicators:stochrsi + https://www.investopedia.com/terms/s/stochrsi.asp + + Args: + close(pandas.Series): dataset 'Close' column. + n(int): n period + d1(int): moving average of Stochastic RSI + d2(int): moving average of %K + fillna(bool): if True, fill nan values. + """ + def __init__(self, close: pd.Series, n: int = 14, d1: int = 3, d2: int = 3, fillna: bool = False): + self._close = close + self._n = n + self._d1 = d1 + self._d2 = d2 + self._fillna = fillna + self._run() + + def _run(self): + self._rsi = RSIIndicator(close=self._close, n=self._n, fillna=self._fillna).rsi() + lowest_low_rsi = self._rsi.rolling(self._n).min() + self._stochrsi = (self._rsi - lowest_low_rsi) / (self._rsi.rolling(self._n).max() - lowest_low_rsi) + + def stochrsi(self): + """Stochastic RSI + + Returns: + pandas.Series: New feature generated. + """ + stochrsi = self._check_fillna(self._stochrsi) + return pd.Series(stochrsi, name='stochrsi') + + def stochrsi_k(self): + """Stochastic RSI %k + + Returns: + pandas.Series: New feature generated. + """ + self.stochrsi_k = self._stochrsi.rolling(self._d1).mean() + stochrsi_K = self._check_fillna(self.stochrsi_k) + return pd.Series(stochrsi_K, name='stochrsi_k') + + def stochrsi_d(self): + """Stochastic RSI %d + + Returns: + pandas.Series: New feature generated. + """ + stochrsi_D = self.stochrsi_k.rolling(self._d2).mean() + stochrsi_D = self._check_fillna(stochrsi_D) + return pd.Series(stochrsi_D, name='stochrsi_d') + + +class PercentagePriceOscillator(IndicatorMixin): + """ + The Percentage Price Oscillator (PPO) is a momentum oscillator that measures + the difference between two moving averages as a percentage of the larger moving average. + + https://school.stockcharts.com/doku.php?id=technical_indicators:price_oscillators_ppo + + Args: + price(pandas.Series): dataset 'Price' column. + n_slow(int): n period long-term. + n_fast(int): n period short-term. + n_sign(int): n period to signal. + fillna(bool): if True, fill nan values. + """ + + def __init__(self, + close: pd.Series, + n_slow: int = 26, + n_fast: int = 12, + n_sign: int = 9, + fillna: bool = False): + self._close = close + self._n_slow = n_slow + self._n_fast = n_fast + self._n_sign = n_sign + self._fillna = fillna + self._run() + + def _run(self): + _emafast = ema(self._close, self._n_fast, self._fillna) + _emaslow = ema(self._close, self._n_slow, self._fillna) + self._ppo = ((_emafast - _emaslow)/_emaslow) * 100 + self._ppo_signal = ema(self._ppo, self._n_sign, self._fillna) + self._ppo_hist = self._ppo - self._ppo_signal + + def ppo(self): + """Percentage Price Oscillator Line + + Returns: + pandas.Series: New feature generated. + """ + ppo = self._check_fillna(self._ppo, value=0) + return pd.Series(ppo, name=f'PPO_{self._n_fast}_{self._n_slow}') + + def ppo_signal(self): + """Percentage Price Oscillator Signal Line + + Returns: + pandas.Series: New feature generated. + """ + + ppo_signal = self._check_fillna(self._ppo_signal, value=0) + return pd.Series(ppo_signal, name=f'PPO_sign_{self._n_fast}_{self._n_slow}') + + def ppo_hist(self): + """Percentage Price Oscillator Histogram + + Returns: + pandas.Series: New feature generated. + """ + + ppo_hist = self._check_fillna(self._ppo_hist, value=0) + return pd.Series(ppo_hist, name=f'PPO_hist_{self._n_fast}_{self._n_slow}') + + +class PercentageVolumeOscillator(IndicatorMixin): + """ + The Percentage Volume Oscillator (PVO) is a momentum oscillator for volume. + The PVO measures the difference between two volume-based moving averages as a + percentage of the larger moving average. + + https://school.stockcharts.com/doku.php?id=technical_indicators:percentage_volume_oscillator_pvo + + Args: + volume(pandas.Series): dataset 'Volume' column. + n_slow(int): n period long-term. + n_fast(int): n period short-term. + n_sign(int): n period to signal. + fillna(bool): if True, fill nan values. + """ + + def __init__(self, + volume: pd.Series, + n_slow: int = 26, + n_fast: int = 12, + n_sign: int = 9, + fillna: bool = False): + self._volume = volume + self._n_slow = n_slow + self._n_fast = n_fast + self._n_sign = n_sign + self._fillna = fillna + self._run() + + def _run(self): + _emafast = ema(self._volume, self._n_fast, self._fillna) + _emaslow = ema(self._volume, self._n_slow, self._fillna) + self._pvo = ((_emafast - _emaslow)/_emaslow) * 100 + self._pvo_signal = ema(self._pvo, self._n_sign, self._fillna) + self._pvo_hist = self._pvo - self._pvo_signal + + def pvo(self): + """PVO Line + + Returns: + pandas.Series: New feature generated. + """ + pvo = self._check_fillna(self._pvo, value=0) + return pd.Series(pvo, name=f'PVO_{self._n_fast}_{self._n_slow}') + + def pvo_signal(self): + """Signal Line + + Returns: + pandas.Series: New feature generated. + """ + + pvo_signal = self._check_fillna(self._pvo_signal, value=0) + return pd.Series(pvo_signal, name=f'PVO_sign_{self._n_fast}_{self._n_slow}') + + def pvo_hist(self): + """Histgram + + Returns: + pandas.Series: New feature generated. + """ + + pvo_hist = self._check_fillna(self._pvo_hist, value=0) + return pd.Series(pvo_hist, name=f'PVO_hist_{self._n_fast}_{self._n_slow}') + + def rsi(close, n=14, fillna=False): """Relative Strength Index (RSI) @@ -719,3 +911,194 @@ def roc(close, n=12, fillna=False): """ return ROCIndicator(close=close, n=n, fillna=fillna).roc() + + +def stochrsi(close, n=14, d1=3, d2=3, fillna=False): + """Stochastic RSI + + The StochRSI oscillator was developed to take advantage of both momentum + indicators in order to create a more sensitive indicator that is attuned to + a specific security's historical performance rather than a generalized analysis + of price change. + + https://www.investopedia.com/terms/s/stochrsi.asp + + Args: + close(pandas.Series): dataset 'Close' column. + n(int): n period + d1(int): moving average of Stochastic RSI + d2(int): moving average of %K + fillna(bool): if True, fill nan values. + Returns: + pandas.Series: New feature generated. + """ + return StochRSIIndicator(close=close, n=n, d1=d1, d2=d2, fillna=fillna).stochrsi() + + +def stochrsi_k(close, n=14, d1=3, d2=3, fillna=False): + """Stochastic RSI %k + + The StochRSI oscillator was developed to take advantage of both momentum + indicators in order to create a more sensitive indicator that is attuned to + a specific security's historical performance rather than a generalized analysis + of price change. + + https://www.investopedia.com/terms/s/stochrsi.asp + + Args: + close(pandas.Series): dataset 'Close' column. + n(int): n period + d1(int): moving average of Stochastic RSI + d2(int): moving average of %K + fillna(bool): if True, fill nan values. + Returns: + pandas.Series: New feature generated. + """ + return StochRSIIndicator(close=close, n=n, d1=d1, d2=d2, fillna=fillna).stochrsi_k() + + +def stochrsi_d(close, n=14, d1=3, d2=3, fillna=False): + """Stochastic RSI %d + + The StochRSI oscillator was developed to take advantage of both momentum + indicators in order to create a more sensitive indicator that is attuned to + a specific security's historical performance rather than a generalized analysis + of price change. + + https://www.investopedia.com/terms/s/stochrsi.asp + + Args: + close(pandas.Series): dataset 'Close' column. + n(int): n period + d1(int): moving average of Stochastic RSI + d2(int): moving average of %K + fillna(bool): if True, fill nan values. + Returns: + pandas.Series: New feature generated. + """ + return StochRSIIndicator(close=close, n=n, d1=d1, d2=d2, fillna=fillna).stochrsi_d() + + +def ppo(close, n_slow=26, n_fast=12, n_sign=9, fillna=False): + """ + The Percentage Price Oscillator (PPO) is a momentum oscillator that measures + the difference between two moving averages as a percentage of the larger moving average. + + https://school.stockcharts.com/doku.php?id=technical_indicators:price_oscillators_ppo + + Args: + price(pandas.Series): dataset 'Price' column. + n_slow(int): n period long-term. + n_fast(int): n period short-term. + n_sign(int): n period to signal. + fillna(bool): if True, fill nan values. + Returns: + pandas.Series: New feature generated. + """ + return PercentagePriceOscillator(close=close, n_slow=n_slow, n_fast=n_fast, n_sign=n_sign, fillna=fillna).ppo() + + +def ppo_signal(close, n_slow=26, n_fast=12, n_sign=9, fillna=False): + """ + The Percentage Price Oscillator (PPO) is a momentum oscillator that measures + the difference between two moving averages as a percentage of the larger moving average. + + https://school.stockcharts.com/doku.php?id=technical_indicators:price_oscillators_ppo + + Args: + price(pandas.Series): dataset 'Price' column. + n_slow(int): n period long-term. + n_fast(int): n period short-term. + n_sign(int): n period to signal. + fillna(bool): if True, fill nan values. + Returns: + pandas.Series: New feature generated. + """ + return PercentagePriceOscillator( + close=close, n_slow=n_slow, n_fast=n_fast, n_sign=n_sign, fillna=fillna).ppo_signal() + + +def ppo_hist(close, n_slow=26, n_fast=12, n_sign=9, fillna=False): + """ + The Percentage Price Oscillator (PPO) is a momentum oscillator that measures + the difference between two moving averages as a percentage of the larger moving average. + + https://school.stockcharts.com/doku.php?id=technical_indicators:price_oscillators_ppo + + Args: + price(pandas.Series): dataset 'Price' column. + n_slow(int): n period long-term. + n_fast(int): n period short-term. + n_sign(int): n period to signal. + fillna(bool): if True, fill nan values. + Returns: + pandas.Series: New feature generated. + """ + return PercentagePriceOscillator( + close=close, n_slow=n_slow, n_fast=n_fast, n_sign=n_sign, fillna=fillna).ppo_hist() + + +def pvo(volume: pd.Series, n_slow: int = 26, n_fast: int = 12, n_sign: int = 9, fillna: bool = False): + """ + The Percentage Volume Oscillator (PVO) is a momentum oscillator for volume. + The PVO measures the difference between two volume-based moving averages as a + percentage of the larger moving average. + + https://school.stockcharts.com/doku.php?id=technical_indicators:percentage_volume_oscillator_pvo + + Args: + volume(pandas.Series): dataset 'Volume' column. + n_slow(int): n period long-term. + n_fast(int): n period short-term. + n_sign(int): n period to signal. + fillna(bool): if True, fill nan values. + Returns: + pandas.Series: New feature generated. + """ + + indicator = PercentageVolumeOscillator(volume=volume, n_slow=n_slow, n_fast=n_fast, n_sign=n_sign, fillna=fillna) + return indicator.pvo() + + +def pvo_signal(volume: pd.Series, n_slow: int = 26, n_fast: int = 12, n_sign: int = 9, fillna: bool = False): + """ + The Percentage Volume Oscillator (PVO) is a momentum oscillator for volume. + The PVO measures the difference between two volume-based moving averages as a + percentage of the larger moving average. + + https://school.stockcharts.com/doku.php?id=technical_indicators:percentage_volume_oscillator_pvo + + Args: + volume(pandas.Series): dataset 'Volume' column. + n_slow(int): n period long-term. + n_fast(int): n period short-term. + n_sign(int): n period to signal. + fillna(bool): if True, fill nan values. + Returns: + pandas.Series: New feature generated. + """ + + indicator = PercentageVolumeOscillator(volume=volume, n_slow=n_slow, n_fast=n_fast, n_sign=n_sign, fillna=fillna) + return indicator.pvo_signal() + + +def pvo_hist(volume: pd.Series, n_slow: int = 26, n_fast: int = 12, n_sign: int = 9, fillna: bool = False): + """ + The Percentage Volume Oscillator (PVO) is a momentum oscillator for volume. + The PVO measures the difference between two volume-based moving averages as a + percentage of the larger moving average. + + https://school.stockcharts.com/doku.php?id=technical_indicators:percentage_volume_oscillator_pvo + + Args: + volume(pandas.Series): dataset 'Volume' column. + n_slow(int): n period long-term. + n_fast(int): n period short-term. + n_sign(int): n period to signal. + fillna(bool): if True, fill nan values. + Returns: + pandas.Series: New feature generated. + """ + + indicator = PercentageVolumeOscillator(volume=volume, n_slow=n_slow, n_fast=n_fast, n_sign=n_sign, fillna=fillna) + return indicator.pvo_hist() diff --git a/ta/tests/__init__.py b/ta/tests/__init__.py index 0fe7ebc3..efeb6a19 100644 --- a/ta/tests/__init__.py +++ b/ta/tests/__init__.py @@ -1,13 +1,18 @@ -from ta.tests.momentum import (TestKAMAIndicator, TestRateOfChangeIndicator, - TestRSIIndicator, TestStochasticOscillator, +from ta.tests.momentum import (TestKAMAIndicator, + TestPercentagePriceOscillator, + TestPercentageVolumeOscillator, + TestRateOfChangeIndicator, TestRSIIndicator, + TestStochasticOscillator, TestStochRSIIndicator, TestTSIIndicator, TestUltimateOscillator, TestWilliamsRIndicator) from ta.tests.trend import (TestADXIndicator, TestCCIIndicator, TestMACDIndicator, TestPSARIndicator, - TestVortexIndicator) + TestSTCIndicator, TestVortexIndicator, + TestWMAIndicator) from ta.tests.volatility import (TestAverageTrueRange, TestAverageTrueRange2, TestBollingerBands, TestDonchianChannel, - TestDonchianChannel2, TestKeltnerChannel) + TestDonchianChannel2, TestKeltnerChannel, + TestUlcerIndex) from ta.tests.volume import (TestAccDistIndexIndicator, TestEaseOfMovementIndicator, TestForceIndexIndicator, TestMFIIndicator, diff --git a/ta/tests/data/cs-ppo.csv b/ta/tests/data/cs-ppo.csv new file mode 100644 index 00000000..5177dcaa --- /dev/null +++ b/ta/tests/data/cs-ppo.csv @@ -0,0 +1,41 @@ +Date,Close,12 day EMA,26 day EMA,PPO,PPO_Signal_Line,PPO_Histogram +13-Apr-10,21.1613,21.1613,21.1613,0,0,0 +14-Apr-10,20.4914,21.05823846,21.11167778,-0.2531268088,-0.05062536176,-0.202501447 +15-Apr-10,20.7377,21.00892485,21.08397572,-0.3559616511,-0.1116926196,-0.2442690315 +16-Apr-10,20.7672,20.97173641,21.06051085,-0.4215208232,-0.1736582603,-0.2478625629 +19-Apr-10,20.5308,20.90390004,21.02127301,-0.5583532883,-0.2505972659,-0.3077560224 +20-Apr-10,19.6146,20.70554619,20.91707501,-1.011273425,-0.4027324978,-0.6085409274 +21-Apr-10,20.0186,20.59986216,20.85052131,-1.202172079,-0.5626204141,-0.6395516654 +22-Apr-10,19.7033,20.46192952,20.76554195,-1.462097307,-0.7425157927,-0.7195815143 +23-Apr-10,19.9397,20.38158652,20.70436847,-1.559004108,-0.9058134557,-0.6531906521 +26-Apr-10,19.6244,20.26509628,20.62437081,-1.741990227,-1.07304881,-0.6689414167 +27-Apr-10,19.1121,20.08771224,20.51235075,-2.070160133,-1.272471075,-0.7976890588 +28-Apr-10,19.3191,19.9694642,20.4239618,-2.225315561,-1.463039972,-0.7622755894 +29-Apr-10,19.6146,19.91486971,20.36400908,-2.205554737,-1.611542925,-0.5940118122 +30-Apr-10,19.5426,19.85759745,20.30316396,-2.194566886,-1.728147717,-0.4664191692 +3-May-10,18.8872,19.70830553,20.19827774,-2.42581182,-1.867680538,-0.558131282 +4-May-10,19.3341,19.65073545,20.13426458,-2.401523646,-1.974449159,-0.4270744866 +5-May-10,19.2149,19.58368384,20.0661635,-2.404443943,-2.060448116,-0.3439958272 +6-May-10,19.5128,19.57277864,20.02517361,-2.25913133,-2.100184759,-0.158946571 +7-May-10,19.5525,19.56965885,19.99016075,-2.103544371,-2.100856681,-0.002687689947 +10-May-10,19.92,19.62355748,19.98496365,-1.808390428,-2.042363431,0.2339730028 +11-May-10,20.2874,19.7256871,20.00736635,-1.407877676,-1.91546628,0.507588604 +12-May-10,20.5753,19.85639678,20.04943551,-0.9628137771,-1.724935779,0.7621220022 +13-May-10,20.5158,19.95784343,20.08398102,-0.6280507625,-1.505558776,0.8775080134 +14-May-10,20.6945,20.07117521,20.12920465,-0.2882848307,-1.262103987,0.9738191561 +17-May-10,20.6746,20.16400979,20.16960431,-0.02773735957,-1.015230661,0.9874933018 +18-May-10,20.7243,20.25020829,20.21069288,0.1955173348,-0.7730810621,0.968598397 +19-May-10,20.2457,20.2495147,20.213286,0.1792321421,-0.5826184213,0.7618505634 +20-May-10,20.5555,20.29658936,20.23863518,0.2863541966,-0.4088238977,0.6951780943 +21-May-10,20.486,20.32572946,20.2569585,0.3394930152,-0.2591605151,0.5986535304 +24-May-10,20.3867,20.33510954,20.26656898,0.3381951862,-0.1396893749,0.477884561 +25-May-10,20.2874,20.32776961,20.26811202,0.2943421294,-0.05288307401,0.3472252034 +26-May-10,20.5753,20.36585121,20.29086669,0.3695481636,0.03160317351,0.3379449901 +27-May-10,20.5158,20.38892026,20.30752841,0.4007963989,0.1054418186,0.2953545803 +28-May-10,20.6945,20.43593252,20.33619298,0.490453395,0.1824441339,0.3080092611 +29-May-10,20.6746,20.4726506,20.36126016,0.5470704372,0.2553693945,0.2917010426 +30-May-10,20.7243,20.51136589,20.388152,0.6043406377,0.3251636432,0.2791769945 +31-May-10,20.2457,20.47049422,20.3776,0.4558643439,0.3513037833,0.1045605606 +1-June-10,20.5555,20.48357203,20.39077778,0.4550794924,0.3720589251,0.08302056727 +2-June-10,20.486,20.48394556,20.39783128,0.4221737262,0.3820818853,0.04009184088 +3-June-10,20.3867,20.46898471,20.39700674,0.3528849535,0.376242499,-0.0233575455 diff --git a/ta/tests/data/cs-pvo.csv b/ta/tests/data/cs-pvo.csv new file mode 100644 index 00000000..e2eaf3f5 --- /dev/null +++ b/ta/tests/data/cs-pvo.csv @@ -0,0 +1,41 @@ +Date,Volume,12 day EMA,26 day EMA,PVO,PVO_Signal_Line,PVO_Histogram +13-Apr-10,45579.000,45579.000,45579.000,0,0,0 +14-Apr-10,66285.000,48764.53846,47112.77778,3.505971759,0.7011943518,2.804777407 +15-Apr-10,51761.000,49225.53254,47457.09053,3.726402081,1.306235898,2.420166184 +16-Apr-10,69341.000,52320.21985,49078.12087,6.605996567,2.366188032,4.239808535 +19-Apr-10,41631.000,50675.72448,48526.48228,4.429008863,2.778752198,1.650256665 +20-Apr-10,73499.000,54186.99764,50376.29841,7.564468511,3.735895461,3.828573051 +21-Apr-10,55427.000,54377.76723,50750.42445,7.147413681,4.418199105,2.729214576 +22-Apr-10,61082.000,55409.18766,51515.72635,7.557811157,5.046121515,2.511689642 +23-Apr-10,33325.000,52011.62033,50168.26514,3.674345101,4.771766232,-1.097421131 +26-Apr-10,39191.000,50039.2172,49355.13438,1.386041846,4.094621355,-2.708579509 +27-Apr-10,51128.000,50206.72225,49486.45776,1.455477954,3.566792675,-2.111314721 +28-Apr-10,46505.000,49637.22652,49265.60904,0.754314182,3.004296976,-2.249982794 +29-Apr-10,44562.000,48856.42244,48917.19356,-0.1242326362,2.378591054,-2.50282369 +30-Apr-10,48815.000,48850.04975,48909.62366,-0.1218040626,1.87851203,-2.000316093 +3-May-10,33411.000,46474.81133,47761.57747,-2.694144966,0.9639806311,-3.658125597 +4-May-10,48157.000,46733.60959,47790.86802,-2.212260375,0.3287324298,-2.540992805 +5-May-10,43199.000,46189.8235,47450.72965,-2.657295607,-0.2684731776,-2.38882243 +6-May-10,45773.000,46125.69681,47326.45338,-2.537178449,-0.7222142319,-1.814964217 +7-May-10,54338.000,47389.12807,47845.8272,-0.9545224015,-0.7686758658,-0.1858465356 +10-May-10,56692.000,48820.33913,48501.09926,0.6582116156,-0.4832983695,1.141509985 +11-May-10,61971.000,50843.51773,49498.86969,2.716522716,0.1566658475,2.559856868 +12-May-10,41212.000,49361.74577,48885.02749,0.9751825961,0.3203691972,0.6548133988 +13-May-10,59785.000,50965.32334,49692.43286,2.561537863,0.7686029304,1.792934933 +14-May-10,44986.000,50045.42744,49343.8082,1.421899253,0.8992621949,0.5226370581 +17-May-10,55929.000,50950.59245,49831.60019,2.245547523,1.168519261,1.077028263 +18-May-10,162619.000,68130.34746,58186.2224,17.09017127,4.352849662,12.73732161 +19-May-10,73914.000,69020.14016,59351.24296,16.29097676,6.740475082,9.550501679 +20-May-10,74485.000,69860.88783,60472.262,15.52550792,8.49748165,7.02802627 +21-May-10,52163.000,67138.13585,59856.76111,12.16466546,9.230918411,2.933747045 +24-May-10,52334.000,64860.57649,59299.51955,9.37791231,9.260317191,0.1175951194 +25-May-10,45579.000,61894.18011,58283.18477,6.195604025,8.647374558,-2.451770532 +26-May-10,66285.000,62569.69086,58875.91182,6.273837509,8.172667148,-1.898829639 +27-May-10,51761.000,60906.81534,58348.88132,4.383861302,7.414905979,-3.031044677 +28-May-10,69341.000,62204.38221,59163.11233,5.140483259,6.960021435,-1.819538176 +29-May-10,41631.000,59039.24649,57864.43734,2.030278355,5.974072819,-3.943794464 +30-May-10,73499.000,61263.82395,59022.55309,3.797312621,5.538720779,-1.741408159 +31-May-10,55427.000,60365.85104,58756.21583,2.739514765,4.978879576,-2.239364811 +1-June-10,61082.000,60476.0278,58928.49614,2.626117692,4.5083272,-1.882209507 +2-June-10,33325.000,56298.9466,57031.94087,-1.285234654,3.349614829,-4.634849483 +3-June-10,39191.000,53666.95482,55710.38969,-3.667960121,1.946099839,-5.61405996 diff --git a/ta/tests/data/cs-stc.csv b/ta/tests/data/cs-stc.csv new file mode 100644 index 00000000..8af798b8 --- /dev/null +++ b/ta/tests/data/cs-stc.csv @@ -0,0 +1,121 @@ +date,Close,short_ema,long_ema,macd_line,_macdmin,_macdmax,_stoch_k,_stoch_d,_stoch_d_min,_stoch_d_max,_stoch_kd,stc +12/10/2010,30.2,30.2,30.2,0,0,0,,0,0,0,0,0 +12/13/2010,30.28,30.20666667,30.20313725,0.003529411765,0,0.003529411765,100,50,0,50,100,50 +12/14/2010,30.45,30.22694444,30.21281815,0.01412629758,0,0.01412629758,100,75,0,75,100,75 +12/15/2010,29.35,30.15386574,30.17898214,-0.02511640037,-0.02511640037,0.01412629758,0,37.5,0,75,50,62.5 +12/16/2010,29.35,30.08687693,30.14647304,-0.05959610852,-0.05959610852,0.01412629758,0,18.75,0,75,25,43.75 +12/17/2010,29.29,30.02047052,30.11288586,-0.09241534133,-0.09241534133,0.01412629758,0,9.375,0,75,12.5,28.125 +12/20/2010,28.83,29.92126464,30.06257661,-0.1413119685,-0.1413119685,0.01412629758,0,4.6875,0,75,6.25,17.1875 +12/21/2010,28.73,29.82199259,30.0103187,-0.1883261157,-0.1883261157,0.01412629758,0,2.34375,0,75,3.125,10.15625 +12/22/2010,28.67,29.72599321,29.95775719,-0.2317639802,-0.2317639802,0.01412629758,0,1.171875,0,75,1.5625,5.859375 +12/23/2010,28.85,29.65299377,29.91431573,-0.2613219558,-0.2613219558,0.01412629758,0,0.5859375,0,75,0.78125,3.3203125 +12/27/2010,28.64,29.56857762,29.86434256,-0.2957649376,-0.2957649376,0.01412629758,0,0.29296875,0.29296875,75,0,1.66015625 +12/28/2010,27.68,29.41119616,29.77868207,-0.3674859137,-0.3674859137,0.01412629758,0,0.146484375,0.146484375,75,0,0.830078125 +12/29/2010,27.21,29.22776314,29.67794944,-0.4501862965,-0.4501862965,-0.02511640037,0,0.0732421875,0.0732421875,37.5,0,0.4150390625 +12/30/2010,26.87,29.03128288,29.56783377,-0.5365508941,-0.5365508941,-0.05959610852,0,0.03662109375,0.03662109375,18.75,0,0.2075195313 +12/31/2010,27.41,28.89617597,29.48321284,-0.5870368685,-0.5870368685,-0.09241534133,0,0.01831054688,0.01831054688,9.375,0,0.1037597656 +1/3/2011,26.94,28.73316131,29.38347901,-0.650317696,-0.650317696,-0.1413119685,0,0.009155273438,0.009155273438,4.6875,0,0.05187988281 +1/4/2011,26.52,28.5487312,29.27118571,-0.7224545108,-0.7224545108,-0.1883261157,0,0.004577636719,0.004577636719,2.34375,0,0.02593994141 +1/5/2011,26.52,28.37967027,29.16329608,-0.7836258085,-0.7836258085,-0.2317639802,0,0.002288818359,0.002288818359,1.171875,0,0.0129699707 +1/6/2011,27.09,28.27219774,29.08199035,-0.8097926023,-0.8097926023,-0.2613219558,0,0.00114440918,0.00114440918,0.5859375,0,0.006484985352 +1/7/2011,27.69,28.22368127,29.02740249,-0.8037212243,-0.8097926023,-0.2957649376,1.181138377,0.5911413929,0.00114440918,0.5911413929,100,50.00324249 +1/10/2011,28.45,28.24254116,29.00475926,-0.7622180949,-0.8097926023,-0.3674859137,10.756,5.673570696,0.00114440918,5.673570696,100,75.00162125 +1/11/2011,28.53,28.26649606,28.98614125,-0.7196451816,-0.8097926023,-0.4501862965,25.06836484,15.37096777,0.00114440918,15.37096777,100,87.50081062 +1/12/2011,28.67,28.30012139,28.97374355,-0.6736221576,-0.8097926023,-0.5365508941,49.8351608,32.60306428,0.00114440918,32.60306428,100,93.75040531 +1/13/2011,29.01,28.35927794,28.97516537,-0.6158874286,-0.8097926023,-0.5870368685,87.04834234,59.82570331,0.00114440918,59.82570331,100,96.87520266 +1/14/2011,29.87,28.48517145,29.01025693,-0.5250854778,-0.8097926023,-0.5250854778,100,79.91285166,0.00114440918,79.91285166,100,98.43760133 +1/18/2011,29.8,28.59474049,29.04122724,-0.4464867484,-0.8097926023,-0.4464867484,100,89.95642583,0.00114440918,89.95642583,100,99.21880066 +1/19/2011,29.75,28.69101212,29.06902225,-0.378010133,-0.8097926023,-0.378010133,100,94.97821291,0.00114440918,94.97821291,100,99.60940033 +1/20/2011,30.65,28.85426111,29.13102138,-0.2767602703,-0.8097926023,-0.2767602703,100,97.48910646,0.00114440918,97.48910646,100,99.80470017 +1/21/2011,30.6,28.99973935,29.18862838,-0.1888890341,-0.8037212243,-0.1888890341,100,98.74455323,0.5911413929,98.74455323,100,99.90235008 +1/24/2011,30.76,29.14642774,29.2502508,-0.1038230629,-0.7622180949,-0.1038230629,100,99.37227661,5.673570696,99.37227661,100,99.95117504 +1/25/2011,30.2,29.23422543,29.28749587,-0.05327044104,-0.7196451816,-0.05327044104,100,99.68613831,15.37096777,99.68613831,100,99.97558752 +1/26/2011,30.28,29.32137331,29.3264176,-0.005044290574,-0.6736221576,-0.005044290574,100,99.84306915,32.60306428,99.84306915,100,99.98779376 +1/27/2011,30.45,29.41542553,29.37047965,0.04494587884,-0.6158874286,0.04494587884,100,99.92153458,59.82570331,99.92153458,100,99.99389688 +1/28/2011,29.35,29.4099734,29.36967653,0.04029687484,-0.5250854778,0.04494587884,99.18443013,99.55298235,79.91285166,99.92153458,98.15803856,99.07596772 +1/29/2011,29.35,29.40497562,29.3689049,0.03607071977,-0.4464867484,0.04494587884,98.19402324,98.87350279,89.95642583,99.92153458,89.482987,94.27947736 +1/30/2011,29.29,29.39539432,29.36581059,0.02958372791,-0.378010133,0.04494587884,96.36790813,97.62070546,94.97821291,99.92153458,53.4558082,73.86764278 +1/31/2011,28.83,29.34827813,29.34479841,0.003479714719,-0.2767602703,0.04494587884,87.11054662,92.36562604,92.36562604,99.92153458,0,36.93382139 +2/1/2011,28.73,29.29675495,29.32068867,-0.0239337208,-0.1888890341,0.04494587884,70.54349209,81.45455906,81.45455906,99.92153458,0,18.4669107 +2/2/2011,28.67,29.24452537,29.29517147,-0.05064609711,-0.1038230629,0.04494587884,35.744669,58.59961403,58.59961403,99.92153458,0,9.233455348 +2/3/2011,28.85,29.21164826,29.27771376,-0.06606550665,-0.06606550665,0.04494587884,0,29.29980702,29.29980702,99.92153458,0,4.616727674 +2/4/2011,28.64,29.1640109,29.25270538,-0.08869447843,-0.08869447843,0.04494587884,0,14.64990351,14.64990351,99.92153458,0,2.308363837 +2/5/2011,27.68,29.04034333,29.19103066,-0.1506873327,-0.1506873327,0.04494587884,0,7.324951754,7.324951754,99.92153458,0,1.154181918 +2/6/2011,27.21,28.88781472,29.11334318,-0.2255284664,-0.2255284664,0.04029687484,0,3.662475877,3.662475877,99.55298235,0,0.5770909592 +2/7/2011,26.87,28.71966349,29.02536894,-0.3057054502,-0.3057054502,0.03607071977,0,1.831237939,1.831237939,98.87350279,0,0.2885454796 +2/8/2011,27.41,28.61052486,28.96202114,-0.3514962728,-0.3514962728,0.02958372791,0,0.9156189693,0.9156189693,97.62070546,0,0.1442727398 +2/9/2011,26.94,28.47131446,28.88272619,-0.4114117316,-0.4114117316,0.003479714719,0,0.4578094846,0.4578094846,92.36562604,0,0.0721363699 +2/10/2011,26.52,28.30870492,28.79007026,-0.4813653408,-0.4813653408,-0.0239337208,0,0.2289047423,0.2289047423,81.45455906,0,0.03606818495 +2/11/2011,26.52,28.15964618,28.7010479,-0.541401721,-0.541401721,-0.05064609711,0,0.1144523712,0.1144523712,58.59961403,0,0.01803409248 +2/12/2011,27.09,28.070509,28.63786955,-0.5673605535,-0.5673605535,-0.06606550665,0,0.05722618558,0.05722618558,29.29980702,0,0.009017046238 +2/13/2011,27.69,28.03879991,28.60069819,-0.5618982817,-0.5673605535,-0.08869447843,1.14114456,0.5991853728,0.05722618558,14.64990351,3.713911952,1.861464499 +2/14/2011,28.45,28.07306659,28.59478846,-0.5217218746,-0.5673605535,-0.1506873327,10.95311065,5.77614801,0.05722618558,7.324951754,78.68929241,40.27537846 +2/15/2011,28.53,28.11114437,28.59224774,-0.4811033662,-0.5673605535,-0.2255284664,25.23378891,15.50496846,0.05722618558,15.50496846,100,70.13768923 +2/16/2011,28.67,28.15771567,28.59529685,-0.4375811722,-0.5673605535,-0.3057054502,49.59940767,32.55218806,0.05722618558,32.55218806,100,85.06884461 +2/17/2011,29.01,28.22873937,28.61155971,-0.3828203471,-0.5673605535,-0.3514962728,85.48899604,59.02059205,0.05722618558,59.02059205,100,92.53442231 +2/18/2011,29.87,28.36551109,28.66091031,-0.2953992272,-0.5673605535,-0.2953992272,100,79.51029603,0.05722618558,79.51029603,100,96.26721115 +2/19/2011,29.8,28.48505183,28.7055805,-0.2205286682,-0.5673605535,-0.2205286682,100,89.75514801,0.05722618558,89.75514801,100,98.13360558 +2/20/2011,29.75,28.59046418,28.74653813,-0.1560739482,-0.5673605535,-0.1560739482,100,94.87757401,0.05722618558,94.87757401,100,99.06680279 +2/21/2011,30.65,28.76209216,28.82118369,-0.05909152668,-0.5673605535,-0.05909152668,100,97.438787,0.05722618558,97.438787,100,99.53340139 +2/22/2011,30.6,28.91525115,28.89094119,0.0243099574,-0.5618982817,0.0243099574,100,98.7193935,0.5991853728,98.7193935,100,99.7667007 +2/23/2011,30.76,29.06898022,28.96423762,0.1047426045,-0.5217218746,0.1047426045,100,99.35969675,5.77614801,99.35969675,100,99.88335035 +2/24/2011,30.2,29.16323187,29.01269889,0.1505329828,-0.4811033662,0.1505329828,100,99.67984838,15.50496846,99.67984838,100,99.94167517 +2/25/2011,30.28,29.25629588,29.06239697,0.1938989109,-0.4375811722,0.1938989109,100,99.83992419,32.55218806,99.83992419,100,99.97083759 +2/26/2011,30.45,29.35577122,29.11681277,0.2389584491,-0.3828203471,0.2389584491,100,99.91996209,59.02059205,99.91996209,100,99.98541879 +2/27/2011,29.35,29.35529029,29.12595737,0.2293329168,-0.2953992272,0.2389584491,98.19867239,99.05931724,79.51029603,99.91996209,95.78315075,97.88428477 +2/28/2011,29.35,29.35484943,29.13474336,0.220106074,-0.2205286682,0.2389584491,95.89708299,97.47820012,89.75514801,99.91996209,75.97829182,86.9312883 +3/1/2011,29.29,29.34944531,29.14083185,0.208613459,-0.1560739482,0.2389584491,92.31835406,94.89827709,94.87757401,99.91996209,0.410580924,43.67093461 +3/2/2011,28.83,29.3061582,29.12864237,0.1775158341,-0.05909152668,0.2389584491,79.38513003,87.14170356,87.14170356,99.91996209,0,21.8354673 +3/3/2011,28.73,29.25814502,29.11300933,0.1451356847,0.0243099574,0.2389584491,56.29004254,71.71587305,71.71587305,99.91996209,0,10.91773365 +3/4/2011,28.67,29.20913293,29.09563642,0.1134965149,0.1047426045,0.2389584491,6.522263039,39.11906804,39.11906804,99.91996209,0,5.458866826 +3/5/2011,28.85,29.17920519,29.08600362,0.09320157116,0.09320157116,0.2389584491,0,19.55953402,19.55953402,99.91996209,0,2.729433413 +3/6/2011,28.64,29.13427142,29.06851328,0.06575814337,0.06575814337,0.2389584491,0,9.779767011,9.779767011,99.91996209,0,1.364716707 +3/7/2011,27.68,29.01308214,29.01406178,-0.0009796407278,-0.0009796407278,0.2389584491,0,4.889883506,4.889883506,99.91996209,0,0.6823583533 +3/8/2011,27.21,28.86282529,28.94331426,-0.08048896482,-0.08048896482,0.2293329168,0,2.444941753,2.444941753,99.05931724,0,0.3411791766 +3/9/2011,26.87,28.69675652,28.86200782,-0.1652512978,-0.1652512978,0.220106074,0,1.222470876,1.222470876,97.47820012,0,0.1705895883 +3/10/2011,27.41,28.58952681,28.80506633,-0.2155395247,-0.2155395247,0.208613459,0,0.6112354382,0.6112354382,94.89827709,0,0.08529479416 +3/11/2011,26.94,28.45206624,28.73192648,-0.2798602358,-0.2798602358,0.1775158341,0,0.3056177191,0.3056177191,87.14170356,0,0.04264739708 +3/12/2011,26.52,28.29106072,28.64518426,-0.3541235412,-0.3541235412,0.1451356847,0,0.1528088596,0.1528088596,71.71587305,0,0.02132369854 +3/13/2011,26.52,28.14347233,28.5618437,-0.4183713753,-0.4183713753,0.1134965149,0,0.07640442978,0.07640442978,39.11906804,0,0.01066184927 +3/14/2011,27.09,28.05568297,28.50412434,-0.448441375,-0.448441375,0.09320157116,0,0.03820221489,0.03820221489,19.55953402,0,0.005330924635 +3/15/2011,27.69,28.02520939,28.4721979,-0.4469885108,-0.448441375,0.06575814337,0.2825487272,0.1603754711,0.03820221489,9.779767011,1.254144059,0.6297374919 +3/16/2011,28.45,28.0606086,28.47132739,-0.4107187873,-0.448441375,-0.0009796407278,8.430349429,4.29536245,0.03820221489,4.889883506,87.74608182,44.18790966 +3/17/2011,28.53,28.09972455,28.47362828,-0.3739037242,-0.448441375,-0.08048896482,20.2574161,12.27638928,0.03820221489,12.27638928,100,72.09395483 +3/18/2011,28.67,28.14724751,28.48132913,-0.3340816222,-0.448441375,-0.1652512978,40.38268357,26.32953642,0.03820221489,26.32953642,100,86.04697741 +3/19/2011,29.01,28.21914355,28.50206132,-0.2829177722,-0.448441375,-0.2155395247,71.07011068,48.69982355,0.03820221489,48.69982355,100,93.02348871 +3/20/2011,29.87,28.35671492,28.55570598,-0.1989910553,-0.448441375,-0.1989910553,100,74.34991177,0.03820221489,74.34991177,100,96.51174435 +3/21/2011,29.8,28.47698868,28.60450182,-0.1275131428,-0.448441375,-0.1275131428,100,87.17495589,0.03820221489,87.17495589,100,98.25587218 +3/22/2011,29.75,28.58307295,28.64942332,-0.0663503631,-0.448441375,-0.0663503631,100,93.58747794,0.03820221489,93.58747794,100,99.12793609 +3/23/2011,30.65,28.75531687,28.7278773,0.02743956986,-0.448441375,0.02743956986,100,96.79373897,0.03820221489,96.79373897,100,99.56396804 +3/24/2011,30.6,28.90904047,28.80129388,0.1077465874,-0.4469885108,0.1077465874,100,98.39686949,0.1603754711,98.39686949,100,99.78198402 +3/25/2011,30.76,29.0632871,28.87810589,0.1851812104,-0.4107187873,0.1851812104,100,99.19843474,4.29536245,99.19843474,100,99.89099201 +3/26/2011,30.2,29.15801317,28.92994487,0.2280683009,-0.3739037242,0.2280683009,100,99.59921737,12.27638928,99.59921737,100,99.94549601 +3/27/2011,30.28,29.25151207,28.98288821,0.2686238649,-0.3340816222,0.2686238649,100,99.79960869,26.32953642,99.79960869,100,99.972748 +3/28/2011,30.45,29.35138607,29.040422,0.310964063,-0.2829177722,0.310964063,100,99.89980434,48.69982355,99.89980434,100,99.986374 +3/29/2011,29.35,29.35127056,29.05256232,0.2987082438,-0.1989910553,0.310964063,97.5966867,98.74824552,74.34991177,99.89980434,95.49290152,97.73963776 +3/30/2011,29.35,29.35116468,29.06422654,0.2869381409,-0.1275131428,0.310964063,94.52059952,96.63442252,87.17495589,99.89980434,74.33854059,86.03908917 +3/31/2011,29.29,29.34606762,29.0730804,0.2729872229,-0.0663503631,0.310964063,89.93496208,93.2846923,93.2846923,99.89980434,0,43.01954459 +4/1/2011,28.83,29.30306199,29.06354784,0.2395141523,0.02743956986,0.310964063,74.79938686,84.04203958,84.04203958,99.89980434,0,21.50977229 +4/2/2011,28.73,29.25530682,29.05046753,0.2048392939,0.1077465874,0.310964063,47.77773476,65.90988717,65.90988717,99.89980434,0,10.75488615 +4/3/2011,28.67,29.20653125,29.03554723,0.1709840205,0.1709840205,0.310964063,0,32.95494359,32.95494359,99.89980434,0,5.377443073 +4/4/2011,28.85,29.17682032,29.02827087,0.1485494448,0.1485494448,0.310964063,0,16.47747179,16.47747179,99.89980434,0,2.688721537 +4/5/2011,28.64,29.13208529,29.01304456,0.1190407271,0.1190407271,0.310964063,0,8.238735896,8.238735896,99.89980434,0,1.344360768 +4/6/2011,27.68,29.01107818,28.96076831,0.0503098769,0.0503098769,0.310964063,0,4.119367948,4.119367948,99.89980434,0,0.6721803842 +4/7/2011,27.21,28.86098833,28.89211073,-0.03112239105,-0.03112239105,0.2987082438,0,2.059683974,2.059683974,98.74824552,0,0.3360901921 +4/8/2011,26.87,28.69507264,28.81281227,-0.1177396258,-0.1177396258,0.2869381409,0,1.029841987,1.029841987,96.63442252,0,0.168045096 +4/9/2011,27.41,28.58798325,28.75780002,-0.1698167667,-0.1698167667,0.2729872229,0,0.5149209935,0.5149209935,93.2846923,0,0.08402254802 +4/10/2011,26.94,28.45065132,28.68651374,-0.2358624292,-0.2358624292,0.2395141523,0,0.2574604968,0.2574604968,84.04203958,0,0.04201127401 +4/11/2011,26.52,28.28976371,28.60155242,-0.3117887155,-0.3117887155,0.2048392939,0,0.1287302484,0.1287302484,65.90988717,0,0.02100563701 +4/12/2011,26.52,28.1422834,28.51992291,-0.3776395176,-0.3776395176,0.1709840205,0,0.06436512419,0.06436512419,32.95494359,0,0.0105028185 +4/13/2011,27.09,28.05459311,28.46384751,-0.4092543923,-0.4092543923,0.1485494448,0,0.03218256209,0.03218256209,16.47747179,0,0.005251409251 +4/14/2011,27.69,28.02421035,28.43350055,-0.4092901907,-0.4092901907,0.1190407271,0,0.01609128105,0.01609128105,8.238735896,0,0.002625704626 +4/15/2011,28.45,28.05969282,28.43414758,-0.3744547577,-0.4092901907,0.0503098769,7.579509985,3.797800633,0.01609128105,4.119367948,92.16315786,46.08289178 +4/16/2011,28.53,28.09888509,28.4379065,-0.3390214114,-0.4092901907,-0.03112239105,18.58137561,11.18958812,0.01609128105,11.18958812,100,73.04144589 +4/17/2011,28.67,28.146478,28.44700821,-0.3005302081,-0.4092901907,-0.1177396258,37.30398624,24.24678718,0.01609128105,24.24678718,100,86.52072295 +4/18/2011,29.01,28.21843817,28.46908632,-0.2506481508,-0.4092901907,-0.1698167667,66.24619852,45.24649285,0.01609128105,45.24649285,100,93.26036147 +4/19/2011,29.87,28.35606832,28.52402411,-0.1679557895,-0.4092901907,-0.1679557895,100,72.62324643,0.01609128105,72.62324643,100,96.63018074 +4/20/2011,29.8,28.47639596,28.57406238,-0.09766641963,-0.4092901907,-0.09766641963,100,86.31162321,0.01609128105,86.31162321,100,98.31509037 +4/21/2011,29.75,28.58252963,28.62017758,-0.03764795036,-0.4092901907,-0.03764795036,100,93.15581161,0.01609128105,93.15581161,100,99.15754518 +4/22/2011,30.65,28.75481883,28.69977846,0.055040368,-0.4092901907,0.055040368,100,96.5779058,0.01609128105,96.5779058,100,99.57877259 +4/23/2011,30.6,28.90858392,28.77429695,0.134286974,-0.4092901907,0.134286974,100,98.2889529,0.01609128105,98.2889529,100,99.7893863 +4/24/2011,30.76,29.0628686,28.85216766,0.2107009391,-0.3744547577,0.2107009391,100,99.14447645,3.797800633,99.14447645,100,99.89469315 \ No newline at end of file diff --git a/ta/tests/data/cs-stochrsi.csv b/ta/tests/data/cs-stochrsi.csv new file mode 100644 index 00000000..795da284 --- /dev/null +++ b/ta/tests/data/cs-stochrsi.csv @@ -0,0 +1,34 @@ +Date,Close,RSI,RSI Highest High (14),RSI Lowest Low (14),StochRSI(14) +14-Dec-09,44.3389000,,,, +15-Dec-09,44.0902000,,,, +16-Dec-09,44.1497000,,,, +17-Dec-09,43.6124000,,,, +18-Dec-09,44.3278000,,,, +21-Dec-09,44.8264000,,,, +22-Dec-09,45.0955000,,,, +23-Dec-09,45.4245000,,,, +24-Dec-09,45.8433000,,,, +28-Dec-09,46.0826000,,,, +29-Dec-09,45.8931000,,,, +30-Dec-09,46.0328000,,,, +31-Dec-09,45.6140000,,,, +04-Jan-10,46.2820000,,,, +05-Jan-10,46.2820000,71.8621140,,, +06-Jan-10,46.0028000,65.2484730,,, +07-Jan-10,46.0328000,65.6146610,,, +08-Jan-10,46.4116000,69.9241170,,, +11-Jan-10,46.2222000,65.5036390,,, +12-Jan-10,45.6439000,54.2305240,,, +13-Jan-10,46.2122000,61.2822820,,, +14-Jan-10,46.2521000,61.7281240,,, +15-Jan-10,45.7137000,52.8795040,,, +19-Jan-10,46.4515000,61.1072270,,, +20-Jan-10,45.7835000,52.2171510,,, +21-Jan-10,45.3548000,47.4464880,,, +22-Jan-10,44.0288000,36.3762260,,, +25-Jan-10,44.1783000,38.1289900,71.8621140,36.3762260,0.0493933 +26-Jan-10,44.2181000,38.6138330,69.9241170,36.3762260,0.0666989 +27-Jan-10,44.5672000,42.8446310,69.9241170,36.3762260,0.1928111 +28-Jan-10,43.4205000,34.4465170,69.9241170,34.4465170,0.0000000 +29-Jan-10,42.6628000,30.2299850,65.5036390,30.2299850,0.0000000 +29-Jan-11,43.1314000,35.4893260,61.7281240,30.2299850,0.1669731 \ No newline at end of file diff --git a/ta/tests/data/cs-ui.csv b/ta/tests/data/cs-ui.csv new file mode 100644 index 00000000..152c97a3 --- /dev/null +++ b/ta/tests/data/cs-ui.csv @@ -0,0 +1,15 @@ +date,Close,max_price,percent_drawdown,percent_drawdown_squared,squared_average,ulcer_index +12/10/2010,199.29,199.29,0,0,, +12/13/2010,199.01,199.29,-0.1404987706,0.001409993182,, +12/14/2010,198.29,199.29,-0.5017813237,0.01798460692,, +12/15/2010,198.4,199.29,-0.4465853781,0.01424560714,, +12/16/2010,200.84,200.84,0,0,, +12/17/2010,201.22,201.22,0,0,, +12/20/2010,200.5,201.22,-0.3578173144,0.009145230748,, +12/21/2010,198.65,201.22,-1.277209025,0.1165187781,, +12/22/2010,197.25,201.22,-1.972964914,0.2780421823,, +12/23/2010,195.7,201.22,-2.743266077,0.5375363406,, +12/27/2010,197.77,201.22,-1.714541298,0.2099751331,, +12/28/2010,195.69,201.22,-2.748235762,0.5394857002,, +12/29/2010,194.87,201.22,-3.155749925,0.711339828,, +12/30/2010,195.08,201.22,-3.051386542,0.6650685592,3.100751959,1.760895215 diff --git a/ta/tests/data/cs-wma.csv b/ta/tests/data/cs-wma.csv new file mode 100644 index 00000000..0135102e --- /dev/null +++ b/ta/tests/data/cs-wma.csv @@ -0,0 +1,41 @@ +Date,Open,High,Low,Close,Volume,WMA +2020-04-09,562.09,575.1818,557.11,573.0,13650000.0,526.1344 +2020-04-13,590.16,652.0,580.53,650.95,22475421.0,553.5311 +2020-04-14,698.97,741.88,692.43,709.89,30576511.0,589.4087 +2020-04-15,742.0,753.13,710.0,729.83,23577001.0,625.1433 +2020-04-16,716.94,759.45,706.715,745.21,20657862.0,658.4369 +2020-04-17,772.28,774.95,747.66,753.89,13128237.0,687.0056 +2020-04-20,732.7,765.57,712.21,746.36,14746577.0,707.982 +2020-04-21,730.12,753.33,673.79,686.72,20209093.0,711.9167 +2020-04-22,703.98,734.0,688.71,732.11,14224831.0,721.79 +2020-04-23,727.6,734.0,703.13,705.63,13236697.0,722.2947 +2020-04-24,710.81,730.73,698.18,725.15,13237612.0,723.756 +2020-04-27,737.61,799.49,735.0,798.75,20681442.0,738.2884 +2020-04-28,795.64,805.0,756.69,769.12,15221964.0,744.9202 +2020-04-29,790.17,803.1999,783.16,800.51,16215982.0,756.9569 +2020-04-30,855.19,869.82,763.5,781.88,28471854.0,764.0387 +2020-05-01,755.0,772.77,683.04,701.32,32531807.0,754.3864 +2020-05-04,701.0,762.0,698.0,761.19,19237090.0,757.7091 +2020-05-05,789.79,798.92,762.18,768.21,16991656.0,760.7809 +2020-05-06,776.5,789.8,761.11,782.58,11123231.0,765.9244 +2020-05-07,777.21,796.4,772.35,780.04,11527686.0,768.85 +2020-05-08,793.77,824.0,787.01,819.42,16130087.0,778.4318 +2020-05-11,790.51,824.0,785.0,811.29,16519601.0,785.9282 +2020-05-12,827.0,843.29,808.0,809.41,15906905.0,792.1116 +2020-05-13,820.83,826.0,763.3,790.96,19065491.0,794.4071 +2020-05-14,780.0,803.36,764.0,803.33,13682188.0,798.9749 +2020-05-15,790.35,805.0486,786.552,799.17,10518428.0,800.4438 +2020-05-18,827.78,834.7201,803.88,813.63,11698102.0,803.9607 +2020-05-19,815.17,822.07,806.08,808.01,9636522.0,805.3442 +2020-05-20,820.5,826.0,811.8,815.56,7309271.0,807.6727 +2020-05-21,816.0,832.5,796.0,827.6,12182524.0,811.6198 +2020-05-22,822.1735,831.78,812.0,816.88,9987475.0,813.2411 +2020-05-26,834.5,834.6,815.705,818.87,8089736.0,815.1362 +2020-05-27,820.86,827.71,785.0,820.23,11549530.0,817.0931 +2020-05-28,813.51,824.75,801.69,805.81,7275774.0,815.5156 +2020-05-29,808.75,835.0,804.21,835.0,11812489.0,819.7209 +2020-06-01,858.0,899.0,854.1,898.1,15085297.0,835.75 +2020-06-02,894.7,908.66,871.0,881.56,13565596.0,846.594 +2020-06-03,888.12,897.94,880.1,882.96,7949469.0,856.0836 +2020-06-04,889.88,895.75,858.44,864.38,8887713.0,860.3593 +2020-06-05,877.84,886.52,866.2,885.66,7811917.0,868.0738 diff --git a/ta/tests/momentum.py b/ta/tests/momentum.py index 7c3e4c54..4a6f95a8 100644 --- a/ta/tests/momentum.py +++ b/ta/tests/momentum.py @@ -2,10 +2,13 @@ import pandas as pd -from ta.momentum import (KAMAIndicator, ROCIndicator, RSIIndicator, - StochasticOscillator, TSIIndicator, - UltimateOscillator, WilliamsRIndicator, kama, roc, - rsi, stoch, stoch_signal, tsi, uo, wr) +from ta.momentum import (KAMAIndicator, PercentagePriceOscillator, + PercentageVolumeOscillator, ROCIndicator, + RSIIndicator, StochasticOscillator, StochRSIIndicator, + TSIIndicator, UltimateOscillator, WilliamsRIndicator, + kama, ppo, ppo_hist, ppo_signal, pvo, pvo_hist, + pvo_signal, roc, rsi, stoch, stoch_signal, stochrsi, + tsi, uo, wr) class TestRateOfChangeIndicator(unittest.TestCase): @@ -65,6 +68,34 @@ def test_rsi2(self): pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) +class TestStochRSIIndicator(unittest.TestCase): + """ + https://school.stockcharts.com/doku.php?id=technical_indicators:stochrsi + """ + + _filename = 'ta/tests/data/cs-stochrsi.csv' + + @classmethod + def setUpClass(cls): + cls._df = pd.read_csv(cls._filename, sep=',') + cls._params = dict(close=cls._df['Close'], n=14, d1=3, d2=3, fillna=False) + cls._indicator = StochRSIIndicator(**cls._params) + + @classmethod + def tearDownClass(cls): + del(cls._df) + + def test_stochrsi(self): + target = 'StochRSI(14)' + result = self._indicator.stochrsi() + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + def test_stochrsi2(self): + target = 'StochRSI(14)' + result = stochrsi(**self._params) + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + class TestUltimateOscillator(unittest.TestCase): """ https://school.stockcharts.com/doku.php?id=technical_indicators:ultimate_oscillator @@ -227,3 +258,113 @@ def test_tsi2(self): result = tsi(**self._params) pd.testing.assert_series_equal( self._df[target].tail(), result.tail(), check_names=False, check_less_precise=True) + + +class TestPercentagePriceOscillator(unittest.TestCase): + """ + https://school.stockcharts.com/doku.php?id=technical_indicators:price_oscillators_ppo + https://docs.google.com/spreadsheets/d/1h9p8_PXU7G8sD-LciydpmH6rveaLwvoL7SMBGmO3kM4/edit#gid=0 + """ + + _filename = 'ta/tests/data/cs-ppo.csv' + + @classmethod + def setUpClass(cls): + cls._df = pd.read_csv(cls._filename, sep=',') + cls._params = dict(close=cls._df['Close'], n_slow=26, n_fast=12, n_sign=9, fillna=True) + cls._indicator = PercentagePriceOscillator(**cls._params) + + @classmethod + def tearDownClass(cls): + del(cls._df) + + def test_ppo(self): + target = 'PPO' + result = self._indicator.ppo() + pd.testing.assert_series_equal( + self._df[target].tail(), result.tail(), check_names=False) + + def test_ppo2(self): + target = 'PPO' + result = ppo(**self._params) + pd.testing.assert_series_equal( + self._df[target].tail(), result.tail(), check_names=False) + + def test_ppo_signal(self): + target = 'PPO_Signal_Line' + result = self._indicator.ppo_signal() + pd.testing.assert_series_equal( + self._df[target].tail(), result.tail(), check_names=False) + + def test_ppo_signal2(self): + target = 'PPO_Signal_Line' + result = ppo_signal(**self._params) + pd.testing.assert_series_equal( + self._df[target].tail(), result.tail(), check_names=False) + + def test_ppo_hist(self): + target = 'PPO_Histogram' + result = self._indicator.ppo_hist() + pd.testing.assert_series_equal( + self._df[target].tail(), result.tail(), check_names=False) + + def test_ppo_hist2(self): + target = 'PPO_Histogram' + result = ppo_hist(**self._params) + pd.testing.assert_series_equal( + self._df[target].tail(), result.tail(), check_names=False) + + +class TestPercentageVolumeOscillator(unittest.TestCase): + """ + https://school.stockcharts.com/doku.php?id=technical_indicators:percentage_volume_oscillator_pvo + https://docs.google.com/spreadsheets/d/1SyePHvrVBAcmjDiXe877Qrycx6TmajyrZ8UdrwVk9MI/edit#gid=0 + """ + + _filename = 'ta/tests/data/cs-pvo.csv' + + @classmethod + def setUpClass(cls): + cls._df = pd.read_csv(cls._filename, sep=',') + cls._params = dict(volume=cls._df['Volume'], n_slow=26, n_fast=12, n_sign=9, fillna=True) + cls._indicator = PercentageVolumeOscillator(**cls._params) + + @classmethod + def tearDownClass(cls): + del(cls._df) + + def test_pvo(self): + target = 'PVO' + result = self._indicator.pvo() + pd.testing.assert_series_equal( + self._df[target].tail(), result.tail(), check_names=False) + + def test_pvo2(self): + target = 'PVO' + result = pvo(**self._params) + pd.testing.assert_series_equal( + self._df[target].tail(), result.tail(), check_names=False) + + def test_pvo_signal(self): + target = 'PVO_Signal_Line' + result = self._indicator.pvo_signal() + pd.testing.assert_series_equal( + self._df[target].tail(), result.tail(), check_names=False) + + def test_pvo_signal2(self): + target = 'PVO_Signal_Line' + result = pvo_signal(**self._params) + pd.testing.assert_series_equal( + self._df[target].tail(), result.tail(), check_names=False) + + def test_pvo_hist(self): + target = 'PVO_Histogram' + result = self._indicator.pvo_hist() + pd.testing.assert_series_equal( + self._df[target].tail(), result.tail(), check_names=False) + + def test_pvo_hist2(self): + target = 'PVO_Histogram' + result = pvo_hist(**self._params) + pd.testing.assert_series_equal( + self._df[target].tail(), result.tail(), check_names=False) diff --git a/ta/tests/trend.py b/ta/tests/trend.py index 1a4777a0..7d79c97a 100644 --- a/ta/tests/trend.py +++ b/ta/tests/trend.py @@ -3,10 +3,11 @@ import pandas as pd from ta.trend import (MACD, ADXIndicator, CCIIndicator, PSARIndicator, - VortexIndicator, adx, adx_neg, adx_pos, cci, macd, - macd_diff, macd_signal, psar_down, psar_down_indicator, - psar_up, psar_up_indicator, vortex_indicator_neg, - vortex_indicator_pos) + STCIndicator, VortexIndicator, WMAIndicator, adx, + adx_neg, adx_pos, cci, macd, macd_diff, macd_signal, + psar_down, psar_down_indicator, psar_up, + psar_up_indicator, stc, vortex_indicator_neg, + vortex_indicator_pos, wma_indicator) class TestADXIndicator(unittest.TestCase): @@ -228,3 +229,59 @@ def test_psar_down_indicator2(self): target = 'psar_down_ind' result = psar_down_indicator(**self._params) pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + +class TestSTCIndicator(unittest.TestCase): + """ + https://www.investopedia.com/articles/forex/10/schaff-trend-cycle-indicator.asp + https://docs.google.com/spreadsheets/d/1z6o_R_hCGCGQARC791KdrOD5E69IhjAXbXqi1014hcs/edit?usp=sharing + """ + + _filename = 'ta/tests/data/cs-stc.csv' + + @classmethod + def setUpClass(cls): + cls._df = pd.read_csv(cls._filename, sep=',') + cls._params = dict(close=cls._df['Close'], n_slow=50, n_fast=23, n=10, d1=3, d2=3, fillna=False) + cls._indicator = STCIndicator(**cls._params) + + @classmethod + def tearDownClass(cls): + del(cls._df) + + def test_stc(self): + target = 'stc' + result = self._indicator.stc() + pd.testing.assert_series_equal(self._df[target].tail(15), result.tail(15), check_names=False) + + def test_stc2(self): + target = 'stc' + result = stc(**self._params) + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + +class TestWMAIndicator(unittest.TestCase): + """ + """ + + _filename = 'ta/tests/data/cs-wma.csv' + + @classmethod + def setUpClass(cls): + cls._df = pd.read_csv(cls._filename, sep=',') + cls._params = dict(close=cls._df['Close'], n=9, fillna=False) + cls._indicator = WMAIndicator(**cls._params) + + @classmethod + def tearDownClass(cls): + del(cls._df) + + def test_wma(self): + target = 'WMA' + result = self._indicator.wma() + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + def test_wma2(self): + target = 'WMA' + result = wma_indicator(**self._params) + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) diff --git a/ta/tests/volatility.py b/ta/tests/volatility.py index afbd0a01..5337f81e 100644 --- a/ta/tests/volatility.py +++ b/ta/tests/volatility.py @@ -3,10 +3,10 @@ import pandas as pd from ta.volatility import (AverageTrueRange, BollingerBands, DonchianChannel, - KeltnerChannel, average_true_range, bollinger_hband, - bollinger_hband_indicator, bollinger_lband, - bollinger_lband_indicator, bollinger_mavg, - bollinger_pband, bollinger_wband, + KeltnerChannel, UlcerIndex, average_true_range, + bollinger_hband, bollinger_hband_indicator, + bollinger_lband, bollinger_lband_indicator, + bollinger_mavg, bollinger_pband, bollinger_wband, donchian_channel_hband, donchian_channel_lband, donchian_channel_mband, donchian_channel_pband, donchian_channel_wband, keltner_channel_hband, @@ -14,7 +14,7 @@ keltner_channel_lband, keltner_channel_lband_indicator, keltner_channel_mband, keltner_channel_pband, - keltner_channel_wband) + keltner_channel_wband, ulcer_index) class TestAverageTrueRange(unittest.TestCase): @@ -391,3 +391,32 @@ def test_lband_indicator2(self): target = 'kc_low_indicator' result = keltner_channel_lband_indicator(**self._params) pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + +class TestUlcerIndex(unittest.TestCase): + """ + https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:ulcer_index + https://docs.google.com/spreadsheets/d/1PpiRxv4Cnjqod9zNTnls4Lfn8lknHFnWk1DmaTZgZC8/edit#gid=0 + """ + + _filename = 'ta/tests/data/cs-ui.csv' + + @classmethod + def setUpClass(cls): + cls._df = pd.read_csv(cls._filename, sep=',') + cls._params = dict(close=cls._df['Close'], n=14, fillna=False) + cls._indicator = UlcerIndex(**cls._params) + + @classmethod + def tearDownClass(cls): + del(cls._df) + + def test_ulcer_index(self): + target = 'ulcer_index' + result = self._indicator.ulcer_index() + pd.testing.assert_series_equal(self._df[target].tail(1), result.tail(1), check_names=False) + + def test_ulcer_index2(self): + target = 'ulcer_index' + result = ulcer_index(**self._params) + pd.testing.assert_series_equal(self._df[target].tail(1), result.tail(1), check_names=False) diff --git a/ta/trend.py b/ta/trend.py index f73bcebd..664c1004 100644 --- a/ta/trend.py +++ b/ta/trend.py @@ -183,6 +183,41 @@ def sma_indicator(self) -> pd.Series: return pd.Series(sma_, name=f'sma_{self._n}') +class WMAIndicator(IndicatorMixin): + """WMA - Weighted Moving Average + + Args: + close(pandas.Series): dataset 'Close' column. + n(int): n period. + fillna(bool): if True, fill nan values. + """ + + def __init__(self, close: pd.Series, n: int = 9, fillna: bool = False): + self._close = close + self._n = n + self._fillna = fillna + self._run() + + def _run(self): + _weight = pd.Series([i*2/(self._n*(self._n+1)) for i in range(1, self._n+1)]) + + def weighted_average(weight): + def _weighted_average(x): + return (weight * x).sum() + return _weighted_average + + self._wma = self._close.rolling(self._n).apply(weighted_average(_weight), raw=True) + + def wma(self) -> pd.Series: + """Weighted Moving Average (WMA) + + Returns: + pandas.Series: New feature generated. + """ + wma = self._check_fillna(self._wma, value=0) + return pd.Series(wma, name=f'wma_{self._n}') + + class TRIXIndicator(IndicatorMixin): """Trix (TRIX) @@ -838,7 +873,7 @@ def psar_down(self) -> pd.Series: return pd.Series(psar_down, name='psardown') def psar_up_indicator(self) -> pd.Series: - """PSAR up trend value + """PSAR up trend value indicator Returns: pandas.Series: New feature generated. @@ -849,7 +884,7 @@ def psar_up_indicator(self) -> pd.Series: return pd.Series(indicator, index=self._close.index, name='psariup') def psar_down_indicator(self) -> pd.Series: - """PSAR down trend value + """PSAR down trend value indicator Returns: pandas.Series: New feature generated. @@ -860,6 +895,70 @@ def psar_down_indicator(self) -> pd.Series: return pd.Series(indicator, index=self._close.index, name='psaridown') +class STCIndicator(IndicatorMixin): + """Schaff Trend Cycle (STC) + + The Schaff Trend Cycle (STC) is a charting indicator that + is commonly used to identify market trends and provide buy + and sell signals to traders. Developed in 1999 by noted currency + trader Doug Schaff, STC is a type of oscillator and is based on + the assumption that, regardless of time frame, currency trends + accelerate and decelerate in cyclical patterns. + + https://www.investopedia.com/articles/forex/10/schaff-trend-cycle-indicator.asp + + Args: + close(pandas.Series): dataset 'Close' column. + n_fast(int): n period short-term. + n_slow(int): n period long-term. + n(int): n period + d1(int): ema period over stoch_k + d2(int): ema period over stoch_kd + fillna(bool): if True, fill nan values. + """ + def __init__(self, + close: pd.Series, + n_slow: int = 50, + n_fast: int = 23, + n: int = 10, + d1: int = 3, + d2: int = 3, + fillna: bool = False): + self._close = close + self._n_slow = n_slow + self._n_fast = n_fast + self._n = n + self._d1 = d1 + self._d2 = d2 + self._fillna = fillna + self._run() + + def _run(self): + + _emafast = ema(self._close, self._n_fast, self._fillna) + _emaslow = ema(self._close, self._n_slow, self._fillna) + _macd = _emafast - _emaslow + + _macdmin = _macd.rolling(window=self._n).min() + _macdmax = _macd.rolling(window=self._n).max() + _stoch_k = 100 * (_macd - _macdmin) / (_macdmax - _macdmin) + _stoch_d = ema(_stoch_k, self._d1, self._fillna) + + _stoch_d_min = _stoch_d.rolling(window=self._n).min() + _stoch_d_max = _stoch_d.rolling(window=self._n).max() + _stoch_kd = 100 * (_stoch_d - _stoch_d_min) / (_stoch_d_max - _stoch_d_min) + self._stc = ema(_stoch_kd, self._d2, self._fillna) + + def stc(self): + """Schaff Trend Cycle + + Returns: + pandas.Series: New feature generated. + """ + stc = self._check_fillna(self._stc) + return pd.Series(stc, name='stc') + + def ema_indicator(close, n=12, fillna=False): """Exponential Moving Average (EMA) @@ -878,6 +977,15 @@ def sma_indicator(close, n=12, fillna=False): return SMAIndicator(close=close, n=n, fillna=fillna).sma_indicator() +def wma_indicator(close, n=9, fillna=False): + """Weighted Moving Average (WMA) + + Returns: + pandas.Series: New feature generated. + """ + return WMAIndicator(close=close, n=n, fillna=fillna).wma() + + def macd(close, n_slow=26, n_fast=12, fillna=False): """Moving Average Convergence Divergence (MACD) @@ -1188,6 +1296,33 @@ def kst(close, r1=10, r2=15, r3=20, r4=30, n1=10, n2=10, n3=10, n4=15, fillna=Fa close=close, r1=r1, r2=r2, r3=r3, r4=r4, n1=n1, n2=n2, n3=n3, n4=n4, nsig=9, fillna=fillna).kst() +def stc(close, n_slow=50, n_fast=23, n=10, d1=3, d2=3, fillna=False): + """Schaff Trend Cycle (STC) + + The Schaff Trend Cycle (STC) is a charting indicator that + is commonly used to identify market trends and provide buy + and sell signals to traders. Developed in 1999 by noted currency + trader Doug Schaff, STC is a type of oscillator and is based on + the assumption that, regardless of time frame, currency trends + accelerate and decelerate in cyclical patterns. + + https://www.investopedia.com/articles/forex/10/schaff-trend-cycle-indicator.asp + + Args: + close(pandas.Series): dataset 'Close' column. + n_fast(int): n period short-term. + n_slow(int): n period long-term. + n(int): n period + d1(int): ema period over stoch_k + d2(int): ema period over stoch_kd + fillna(bool): if True, fill nan values. + + Returns: + pandas.Series: New feature generated. + """ + return STCIndicator(close=close, n_slow=n_slow, n_fast=n_fast, n=n, d1=d1, d2=d2, fillna=fillna).stc() + + def kst_sig(close, r1=10, r2=15, r3=20, r4=30, n1=10, n2=10, n3=10, n4=15, nsig=9, fillna=False): """KST Oscillator (KST Signal) diff --git a/ta/volatility.py b/ta/volatility.py index 1ad855c4..29153529 100644 --- a/ta/volatility.py +++ b/ta/volatility.py @@ -372,6 +372,44 @@ def donchian_channel_pband(self) -> pd.Series: return pd.Series(pband, name='dcpband') +class UlcerIndex(IndicatorMixin): + """Ulcer Index + + https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:ulcer_index + + Args: + close(pandas.Series): dataset 'Close' column. + n(int): n period. + fillna(bool): if True, fill nan values. + """ + + def __init__(self, close: pd.Series, n: int = 14, fillna: bool = False): + self._close = close + self._n = n + self._fillna = fillna + self._run() + + def _run(self): + _ui_max = self._close.rolling(self._n, min_periods=1).max() + _r_i = 100 * (self._close - _ui_max) / _ui_max + + def ui_function(): + def _ui_function(x): + return np.sqrt((x**2/self._n).sum()) + return _ui_function + + self._ui = _r_i.rolling(self._n).apply(ui_function(), raw=True) + + def ulcer_index(self) -> pd.Series: + """Ulcer Index (UI) + + Returns: + pandas.Series: New feature generated. + """ + ui = self._check_fillna(self._ui) + return pd.Series(ui, name='ui') + + def average_true_range(high, low, close, n=14, fillna=False): """Average True Range (ATR) @@ -801,3 +839,20 @@ def donchian_channel_pband(high, low, close, n=10, offset=0, fillna=False): """ indicator = DonchianChannel(high=high, low=low, close=close, n=n, offset=offset, fillna=fillna) return indicator.donchian_channel_pband() + + +def ulcer_index(close, n=14, fillna=False): + """Ulcer Index + + https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:ulcer_index + + Args: + close(pandas.Series): dataset 'Close' column. + n(int): n period. + fillna(bool): if True, fill nan values. + + Returns: + pandas.Series: New feature generated. + """ + indicator = UlcerIndex(close=close, n=n, fillna=fillna) + return indicator.ulcer_index() diff --git a/ta/wrapper.py b/ta/wrapper.py index 527df5f9..5b4162d6 100644 --- a/ta/wrapper.py +++ b/ta/wrapper.py @@ -8,16 +8,18 @@ import pandas as pd from ta.momentum import (AwesomeOscillatorIndicator, KAMAIndicator, + PercentagePriceOscillator, PercentageVolumeOscillator, ROCIndicator, RSIIndicator, StochasticOscillator, - TSIIndicator, UltimateOscillator, WilliamsRIndicator) + StochRSIIndicator, TSIIndicator, UltimateOscillator, + WilliamsRIndicator) from ta.others import (CumulativeReturnIndicator, DailyLogReturnIndicator, DailyReturnIndicator) from ta.trend import (MACD, ADXIndicator, AroonIndicator, CCIIndicator, DPOIndicator, EMAIndicator, IchimokuIndicator, KSTIndicator, MassIndex, PSARIndicator, SMAIndicator, - TRIXIndicator, VortexIndicator) + STCIndicator, TRIXIndicator, VortexIndicator) from ta.volatility import (AverageTrueRange, BollingerBands, DonchianChannel, - KeltnerChannel) + KeltnerChannel, UlcerIndex) from ta.volume import (AccDistIndexIndicator, ChaikinMoneyFlowIndicator, EaseOfMovementIndicator, ForceIndexIndicator, MFIIndicator, NegativeVolumeIndexIndicator, @@ -131,6 +133,9 @@ def add_volatility_ta(df: pd.DataFrame, high: str, low: str, close: str, df[f'{colprefix}volatility_dcw'] = indicator_dc.donchian_channel_wband() df[f'{colprefix}volatility_dcp'] = indicator_dc.donchian_channel_pband() + # Ulcer Index + df[f'{colprefix}volatility_ui'] = UlcerIndex(close=df[close], n=14, fillna=fillna) + return df @@ -229,6 +234,10 @@ def add_trend_ta(df: pd.DataFrame, high: str, low: str, close: str, fillna: bool df[f'{colprefix}trend_psar_up_indicator'] = indicator.psar_up_indicator() df[f'{colprefix}trend_psar_down_indicator'] = indicator.psar_down_indicator() + # Schaff Trend Cycle (STC) + df[f'{colprefix}trend_stc'] = STCIndicator( + close=df[close], n_slow=50, n_fast=23, n=10, d1=3, d2=3, fillna=fillna).stc() + return df @@ -251,6 +260,12 @@ def add_momentum_ta(df: pd.DataFrame, high: str, low: str, close: str, volume: s # Relative Strength Index (RSI) df[f'{colprefix}momentum_rsi'] = RSIIndicator(close=df[close], n=14, fillna=fillna).rsi() + # Stoch RSI (StochRSI) + indicator = StochRSIIndicator(close=df[close], n=14, d1=3, d2=3, fillna=fillna) + df[f'{colprefix}momentum_stoch_rsi'] = indicator.stochrsi() + df[f'{colprefix}momentum_stoch_rsi_k'] = indicator.stochrsi_k() + df[f'{colprefix}momentum_stoch_rsi_d'] = indicator.stochrsi_d() + # TSI Indicator df[f'{colprefix}momentum_tsi'] = TSIIndicator(close=df[close], r=25, s=13, fillna=fillna).tsi() @@ -278,6 +293,19 @@ def add_momentum_ta(df: pd.DataFrame, high: str, low: str, close: str, volume: s # Rate Of Change df[f'{colprefix}momentum_roc'] = ROCIndicator(close=df[close], n=12, fillna=fillna).roc() + + # Percentage Price Oscillator + indicator = PercentagePriceOscillator(close=df[close], n_slow=26, n_fast=12, n_sign=9, fillna=fillna) + df[f'{colprefix}momentum_ppo'] = indicator.ppo() + df[f'{colprefix}momentum_ppo_signal'] = indicator.ppo_signal() + df[f'{colprefix}momentum_ppo_hist'] = indicator.ppo_hist() + + # Percentage Volume Oscillator + indicator = PercentageVolumeOscillator(volume=df[volume], n_slow=26, n_fast=12, n_sign=9, fillna=fillna) + df[f'{colprefix}momentum_ppo'] = indicator.pvo() + df[f'{colprefix}momentum_ppo_signal'] = indicator.pvo_signal() + df[f'{colprefix}momentum_ppo_hist'] = indicator.pvo_hist() + return df