mirror of
https://github.com/wassname/pandas-ta.git
synced 2026-09-12 12:40:39 +08:00
@@ -7,5 +7,8 @@ caches:
|
||||
init:
|
||||
pip install -r requirements.txt
|
||||
|
||||
test:
|
||||
python -m unittest -v
|
||||
ti:
|
||||
python -m unittest -v tests/test_indicator*.py
|
||||
|
||||
ts:
|
||||
python -m unittest -v tests/test_strategy.py
|
||||
@@ -7,7 +7,7 @@
|
||||
# Pandas Technical Analysis Library in _Python 3_
|
||||

|
||||
|
||||
_Pandas Technical Analysis_ (**Pandas TA**) is an easy to use library that is built upon Python's Pandas library with more than 115 Indicators and Utility functions. These indicators are commonly used for financial time series datasets with columns or labels: datetime, _open_, _high_, _low_, _close_, _volume_, et al. Many commonly used indicators are included, such as: _Simple Moving Average_ (**sma**) _Moving Average Convergence Divergence_ (**macd**), _Hull Exponential Moving Average_ (**hma**), _Bollinger Bands_ (**bbands**), _On-Balance Volume_ (**obv**), _Aroon & Aroon Oscillator_ (**aroon**), _Squeeze_ (**squeeze**) and **many more**.
|
||||
_Pandas Technical Analysis_ (**Pandas TA**) is an easy to use library that is built upon Python's Pandas library with more than 120 Indicators and Utility functions. These indicators are commonly used for financial time series datasets with columns or labels: datetime, _open_, _high_, _low_, _close_, _volume_, et al. Many commonly used indicators are included, such as: _Simple Moving Average_ (**sma**) _Moving Average Convergence Divergence_ (**macd**), _Hull Exponential Moving Average_ (**hma**), _Bollinger Bands_ (**bbands**), _On-Balance Volume_ (**obv**), _Aroon & Aroon Oscillator_ (**aroon**), _Squeeze_ (**squeeze**) and **many more**.
|
||||
|
||||
**Pandas TA** has three different ways of processing Technical Indicators as described below. The **primary** requirement to run indicators in [Pandas DataFrame Extension](https://pandas.pydata.org/pandas-docs/stable/extending.html) mode, is that _open, high, low, close, volume_ are **lowercase**. Depending on the indicator, they either return a named Series or a DataFrame in uppercase underscore parameter format. For example, MACD(fast=12, slow=26, signal=9) will return a DataFrame with columns: ['MACD_12_26_9', 'MACDh_12_26_9', 'MACDs_12_26_9'].
|
||||
|
||||
@@ -29,7 +29,7 @@ Please take a moment to read **this** and the rest of this **README** before pos
|
||||
* Documentation could always use improvement. Can you contribute?
|
||||
|
||||
* ### [Indicator or Feature Requests & Contributions](https://github.com/twopirllc/pandas-ta/issues)
|
||||
* Please be as detailed and concise as possible. Links and screenshots and sometimes data samples are welcome.
|
||||
* Please be as detailed as possible. Links, screenshots, and sometimes data samples are welcome.
|
||||
* You want a new indicator not currently listed.
|
||||
* You want an alternate version of an existing indicator.
|
||||
* The indicator does not match another website, library, broker platform, language, et al.
|
||||
@@ -38,7 +38,7 @@ Please take a moment to read **this** and the rest of this **README** before pos
|
||||
|
||||
## __Features__
|
||||
|
||||
* Has 115+ indicators and utility functions.
|
||||
* Has 120+ indicators and utility functions.
|
||||
* Easily add prefixes or suffixes or both to columns names. Useful for building Custom Strategies.
|
||||
* __Extended Pandas DataFrame__ as 'ta'.
|
||||
* Indicators are tightly correlated with the de facto [TA Lib](https://mrjbq7.github.io/ta-lib/) if they share common indicators.
|
||||
@@ -55,6 +55,9 @@ and _Weighted Moving Average_.
|
||||
* Updated *trend_return* utility to return a more pertinenet trade info for a _trend_. Example can be found in the [AI Example Notebook](https://github.com/twopirllc/pandas-ta/tree/master/examples/AIExample.ipynb). The notebook is still a work in progress and open to colloboration.
|
||||
|
||||
|
||||
## __Breaking Indicators__
|
||||
* _Stochastic Oscillator_ (**stoch**): Now in line with Trading View's calculation. See: ```help(ta.stoch)```
|
||||
|
||||
## __New Indicators__
|
||||
* _Squeeze_ (**squeeze**). A Momentum indicator. Both John Carter's TTM **and** Lazybear's TradingView versions are implemented. The default is John Carter's, or ```lazybear=False```. Set ```lazybear=True``` to enable Lazybear's.
|
||||
* _TTM Trend_ (**ttm_trend**). A trend indicator inspired from John Carter's book "Mastering the Trade".
|
||||
@@ -62,6 +65,7 @@ and _Weighted Moving Average_.
|
||||
* _Gann High-Low Activator_ (**hilo**) The Gann High Low Activator Indicator was created by Robert Krausz in a 1998
|
||||
issue of Stocks & Commodities Magazine. It is a moving average based trend
|
||||
indicator consisting of two different simple moving averages.
|
||||
* _Stochastic RSI_ (**stochrsi**) "Stochastic RSI and Dynamic Momentum Index" was created by Tushar Chande and Stanley Kroll. In line with Trading View's calculation. See: ```help(ta.stochrsi)```
|
||||
|
||||
## __Updated Indicators__
|
||||
* _Fisher Transform_ (**fisher**): Added Fisher's default **ema** signal line. To change the length of the signal line, use the argument: ```signal=5```. Default: 5
|
||||
@@ -321,7 +325,7 @@ print(bothhl2.name) # "pre_HL2_post"
|
||||
* _Doji_: **cdl_doji**
|
||||
* _Heikin-Ashi_: **ha**
|
||||
|
||||
## _Momentum_ (32)
|
||||
## _Momentum_ (33)
|
||||
|
||||
* _Awesome Oscillator_: **ao**
|
||||
* _Absolute Price Oscillator_: **apo**
|
||||
@@ -350,8 +354,9 @@ print(bothhl2.name) # "pre_HL2_post"
|
||||
* _Slope_: **slope**
|
||||
* _SMI Ergodic_ **smi**
|
||||
* _Squeeze_: **squeeze**
|
||||
* Default is John Carter's. Enable Lazybear's by ```lazybear=True```
|
||||
* Default is John Carter's. Enable Lazybear's with ```lazybear=True```
|
||||
* _Stochastic Oscillator_: **stoch**
|
||||
* _Stochastic RSI_: **stochrsi**
|
||||
* _Trix_: **trix**
|
||||
* _True strength index_: **tsi**
|
||||
* _Ultimate Oscillator_: **uo**
|
||||
@@ -501,6 +506,7 @@ Use parameter: cumulative=**True** for cumulative results.
|
||||
* [allahyarzadeh](https://github.com/allahyarzadeh)
|
||||
* [FGU1](https://github.com/FGU1)
|
||||
* [lluissalord](https://github.com/lluissalord)
|
||||
* [SoftDevDanial](https://github.com/SoftDevDanial)
|
||||
* [YuvalWein](https://github.com/YuvalWein)
|
||||
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ Category = {
|
||||
"candles": ["cdl_doji", "ha"],
|
||||
|
||||
# Momentum
|
||||
"momentum": ["ao", "apo", "bias", "bop", "brar", "cci", "cg", "cmo", "coppock", "er", "eri", "fisher", "inertia", "kdj", "kst", "macd", "mom", "pgo", "ppo", "psl", "pvo", "roc", "rsi", "rvgi", "slope", "smi", "squeeze", "stoch", "trix", "tsi", "uo", "willr"],
|
||||
"momentum": ["ao", "apo", "bias", "bop", "brar", "cci", "cg", "cmo", "coppock", "er", "eri", "fisher", "inertia", "kdj", "kst", "macd", "mom", "pgo", "ppo", "psl", "pvo", "roc", "rsi", "rvgi", "slope", "smi", "squeeze", "stoch", "stochrsi", "trix", "tsi", "uo", "willr"],
|
||||
|
||||
# Overlap
|
||||
"overlap": ["dema", "ema", "fwma", "hilo", "hl2", "hlc3", "hma", "ichimoku", "kama", "linreg", "midpoint", "midprice", "ohlc4", "pwma", "rma", "sinwma", "sma", "supertrend", "swma", "t3", "tema", "trima", "vwap", "vwma", "wcp", "wma", "zlma"],
|
||||
|
||||
+11
-4
@@ -23,7 +23,7 @@ from pandas_ta.volatility import *
|
||||
from pandas_ta.volume import *
|
||||
from pandas_ta.utils import *
|
||||
|
||||
version = ".".join(("0", "2", "00b"))
|
||||
version = ".".join(("0", "2", "01b"))
|
||||
|
||||
|
||||
def mp_worker(args):
|
||||
@@ -146,7 +146,7 @@ class BasePandasObject(PandasObject):
|
||||
# Preemptively drop the rows that are all nas
|
||||
# Might need to be moved to AnalysisIndicators.__call__() to be
|
||||
# toggleable via kwargs.
|
||||
df.dropna(axis=0, inplace=True)
|
||||
# df.dropna(axis=0, inplace=True)
|
||||
# Preemptively rename columns to lowercase
|
||||
df.rename(columns=common_names, errors="ignore", inplace=True)
|
||||
|
||||
@@ -643,13 +643,13 @@ class AnalysisIndicators(BasePandasObject):
|
||||
return result
|
||||
|
||||
@finalize
|
||||
def bop(self, open_=None, high=None, low=None, close=None, percentage=False, offset=None, **kwargs):
|
||||
def bop(self, open_=None, high=None, low=None, close=None, scalar=None, offset=None, **kwargs):
|
||||
open_ = self._get_column(open_, "open")
|
||||
high = self._get_column(high, "high")
|
||||
low = self._get_column(low, "low")
|
||||
close = self._get_column(close, "close")
|
||||
|
||||
result = bop(open_=open_, high=high, low=low, close=close, percentage=percentage, offset=offset, **kwargs)
|
||||
result = bop(open_=open_, high=high, low=low, close=close, scalar=scalar, offset=offset, **kwargs)
|
||||
return result
|
||||
|
||||
@finalize
|
||||
@@ -848,6 +848,13 @@ class AnalysisIndicators(BasePandasObject):
|
||||
result = stoch(high=high, low=low, close=close, fast_k=fast_k, slow_k=slow_k, slow_d=slow_d, offset=offset, **kwargs)
|
||||
return result
|
||||
|
||||
@finalize
|
||||
def stochrsi(self, close=None, length=None, rsi_length=None, k=None, d=None, offset=None, **kwargs):
|
||||
close = self._get_column(close, "close")
|
||||
|
||||
result = stochrsi(close=close, length=length, rsi_length=rsi_length, k=k, d=d, offset=offset, **kwargs)
|
||||
return result
|
||||
|
||||
@finalize
|
||||
def trix(self, close=None, length=None, signal=None, scalar=None, drift=None, offset=None, **kwargs):
|
||||
close = self._get_column(close, "close")
|
||||
|
||||
@@ -27,6 +27,7 @@ from .slope import slope
|
||||
from .smi import smi
|
||||
from .squeeze import squeeze
|
||||
from .stoch import stoch
|
||||
from .stochrsi import stochrsi
|
||||
from .trix import trix
|
||||
from .tsi import tsi
|
||||
from .uo import uo
|
||||
|
||||
@@ -1,33 +1,34 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from ..utils import get_offset, non_zero_range, verify_series
|
||||
|
||||
def bop(open_, high, low, close, offset=None, **kwargs):
|
||||
def bop(open_, high, low, close, scalar=None, offset=None, **kwargs):
|
||||
"""Indicator: Balance of Power (BOP)"""
|
||||
# Validate Arguments
|
||||
open_ = verify_series(open_)
|
||||
high = verify_series(high)
|
||||
low = verify_series(low)
|
||||
close = verify_series(close)
|
||||
scalar = float(scalar) if scalar else 1
|
||||
high_low_range = non_zero_range(high, low)
|
||||
close_open_range = non_zero_range(close, open_)
|
||||
offset = get_offset(offset)
|
||||
|
||||
# Calculate Result
|
||||
bop = close_open_range / high_low_range
|
||||
bop = scalar * close_open_range / high_low_range
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
bop = bop.shift(offset)
|
||||
|
||||
# Handle fills
|
||||
if 'fillna' in kwargs:
|
||||
bop.fillna(kwargs['fillna'], inplace=True)
|
||||
if 'fill_method' in kwargs:
|
||||
bop.fillna(method=kwargs['fill_method'], inplace=True)
|
||||
if "fillna" in kwargs:
|
||||
bop.fillna(kwargs["fillna"], inplace=True)
|
||||
if "fill_method" in kwargs:
|
||||
bop.fillna(method=kwargs["fill_method"], inplace=True)
|
||||
|
||||
# Name and Categorize it
|
||||
bop.name = f"BOP"
|
||||
bop.category = 'momentum'
|
||||
bop.category = "momentum"
|
||||
|
||||
return bop
|
||||
|
||||
@@ -42,14 +43,15 @@ Sources:
|
||||
http://www.worden.com/TeleChartHelp/Content/Indicators/Balance_of_Power.htm
|
||||
|
||||
Calculation:
|
||||
BOP = (close - open) / (high - low)
|
||||
BOP = scalar * (close - open) / (high - low)
|
||||
|
||||
Args:
|
||||
open (pd.Series): Series of 'open's
|
||||
high (pd.Series): Series of 'high's
|
||||
low (pd.Series): Series of 'low's
|
||||
close (pd.Series): Series of 'close's
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
scalar (float): How much to magnify. Default: 1
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
|
||||
+49
-51
@@ -1,95 +1,93 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import DataFrame
|
||||
from ..overlap.sma import sma
|
||||
from ..utils import get_offset, non_zero_range, verify_series
|
||||
from pandas_ta.overlap import sma
|
||||
from pandas_ta.utils import get_offset, non_zero_range, verify_series
|
||||
|
||||
def stoch(high, low, close, fast_k=None, slow_k=None, slow_d=None, offset=None, **kwargs):
|
||||
def stoch(high, low, close, k=None, d=None, smooth_k=None, offset=None, **kwargs):
|
||||
"""Indicator: Stochastic Oscillator (STOCH)"""
|
||||
# Validate arguments
|
||||
high = verify_series(high)
|
||||
low = verify_series(low)
|
||||
close = verify_series(close)
|
||||
fast_k = fast_k if fast_k and fast_k > 0 else 14
|
||||
slow_k = slow_k if slow_k and slow_k > 0 else 5
|
||||
slow_d = slow_d if slow_d and slow_d > 0 else 3
|
||||
k = k if k and k > 0 else 14
|
||||
d = d if d and d > 0 else 3
|
||||
smooth_k = smooth_k if smooth_k and smooth_k > 0 else 3
|
||||
offset = get_offset(offset)
|
||||
|
||||
# Calculate Result
|
||||
lowest_low = low.rolling(fast_k).min()
|
||||
highest_high = high.rolling(fast_k).max()
|
||||
lowest_low = low.rolling(k).min()
|
||||
highest_high = high.rolling(k).max()
|
||||
|
||||
fastk = 100 * (close - lowest_low) / non_zero_range(highest_high, lowest_low)
|
||||
fastd = sma(fastk, length=slow_d)
|
||||
stoch = 100 * (close - lowest_low)
|
||||
stoch /= non_zero_range(highest_high, lowest_low)
|
||||
|
||||
slowk = sma(fastk, length=slow_k)
|
||||
slowd = sma(slowk, length=slow_d)
|
||||
stoch_k = sma(stoch, length=smooth_k)
|
||||
stoch_d = sma(stoch_k, length=d)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
fastk = fastk.shift(offset)
|
||||
fastd = fastd.shift(offset)
|
||||
slowk = slowk.shift(offset)
|
||||
slowd = slowd.shift(offset)
|
||||
stoch_k = stoch_k.shift(offset)
|
||||
stoch_d = stoch_d.shift(offset)
|
||||
|
||||
# Handle fills
|
||||
if 'fillna' in kwargs:
|
||||
fastk.fillna(kwargs['fillna'], inplace=True)
|
||||
fastd.fillna(kwargs['fillna'], inplace=True)
|
||||
slowk.fillna(kwargs['fillna'], inplace=True)
|
||||
slowd.fillna(kwargs['fillna'], inplace=True)
|
||||
if 'fill_method' in kwargs:
|
||||
fastk.fillna(method=kwargs['fill_method'], inplace=True)
|
||||
fastd.fillna(method=kwargs['fill_method'], inplace=True)
|
||||
slowk.fillna(method=kwargs['fill_method'], inplace=True)
|
||||
slowd.fillna(method=kwargs['fill_method'], inplace=True)
|
||||
if "fillna" in kwargs:
|
||||
stoch_k.fillna(kwargs["fillna"], inplace=True)
|
||||
stoch_d.fillna(kwargs["fillna"], inplace=True)
|
||||
if "fill_method" in kwargs:
|
||||
stoch_k.fillna(method=kwargs["fill_method"], inplace=True)
|
||||
stoch_d.fillna(method=kwargs["fill_method"], inplace=True)
|
||||
|
||||
# Name and Categorize it
|
||||
fastk.name = f"STOCHFk_{fast_k}"
|
||||
fastd.name = f"STOCHFd_{slow_d}"
|
||||
slowk.name = f"STOCHk_{slow_k}"
|
||||
slowd.name = f"STOCHd_{slow_d}"
|
||||
fastk.category = fastd.category = slowk.category = slowd.category = 'momentum'
|
||||
_name = "STOCH"
|
||||
_props = f"_{k}_{d}_{smooth_k}"
|
||||
stoch_k.name = f"{_name}k{_props}"
|
||||
stoch_d.name = f"{_name}d{_props}"
|
||||
stoch_k.category = stoch_d.category = "momentum"
|
||||
|
||||
# Prepare DataFrame to return
|
||||
_props = f"_{fast_k}_{slow_k}_{slow_d}"
|
||||
data = {fastk.name: fastk, fastd.name: fastd, slowk.name: slowk, slowd.name: slowd}
|
||||
stochdf = DataFrame(data)
|
||||
stochdf.name = f"STOCH{_props}"
|
||||
stochdf.category = 'momentum'
|
||||
data = {stoch_k.name: stoch_k, stoch_d.name: stoch_d}
|
||||
df = DataFrame(data)
|
||||
df.name = f"{_name}{_props}"
|
||||
df.category = stoch_k.category
|
||||
|
||||
return stochdf
|
||||
return df
|
||||
|
||||
|
||||
|
||||
stoch.__doc__ = \
|
||||
"""Stochastic (STOCH)
|
||||
|
||||
Stochastic Oscillator is a range bound momentum indicator. It displays the location
|
||||
of the close relative to the high-low range over a period.
|
||||
The Stochastic Oscillator (STOCH) was developed by George Lane in the 1950's.
|
||||
He believed this indicator was a good way to measure momentum because changes in
|
||||
momentum precede changes in price.
|
||||
|
||||
It is a range-bound oscillator with two lines moving between 0 and 100.
|
||||
The first line (%K) displays the current close in relation to the period's
|
||||
high/low range. The second line (%D) is a Simple Moving Average of the %K line.
|
||||
The most common choices are a 14 period %K and a 3 period SMA for %D.
|
||||
|
||||
Sources:
|
||||
https://www.tradingview.com/wiki/Stochastic_(STOCH)
|
||||
https://www.sierrachart.com/index.php?page=doc/StudiesReference.php&ID=332&Name=KD_-_Slow
|
||||
|
||||
Calculation:
|
||||
Default Inputs:
|
||||
fast_k=14, slow_k=5, slow_d=3
|
||||
k=14, d=3, smooth_k=3
|
||||
SMA = Simple Moving Average
|
||||
LL = low for last fast_k periods
|
||||
HH = high for last fast_k periods
|
||||
LL = low for last k periods
|
||||
HH = high for last k periods
|
||||
|
||||
FASTK = 100 * (close - LL) / (HH - LL)
|
||||
FASTD = SMA(FASTK, slow_d)
|
||||
|
||||
SLOWK = SMA(FASTK, slow_k)
|
||||
SLOWD = SMA(SLOWK, slow_d)
|
||||
STOCH = 100 * (close - LL) / (HH - LL)
|
||||
STOCHk = SMA(STOCH, smooth_k)
|
||||
STOCHd = SMA(FASTK, d)
|
||||
|
||||
Args:
|
||||
high (pd.Series): Series of 'high's
|
||||
low (pd.Series): Series of 'low's
|
||||
close (pd.Series): Series of 'close's
|
||||
fast_k (int): The Fast %K period. Default: 14
|
||||
slow_k (int): The Slow %K period. Default: 5
|
||||
slow_d (int): The Slow %D period. Default: 3
|
||||
k (int): The Fast %K period. Default: 14
|
||||
d (int): The Slow %K period. Default: 3
|
||||
smooth_k (int): The Slow %D period. Default: 3
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
@@ -97,5 +95,5 @@ Kwargs:
|
||||
fill_method (value, optional): Type of fill method
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: fastk, fastd, slowk, slowd columns.
|
||||
pd.DataFrame: %K, %D columns.
|
||||
"""
|
||||
@@ -0,0 +1,102 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import DataFrame
|
||||
from .rsi import rsi
|
||||
from pandas_ta.overlap import sma
|
||||
from pandas_ta.utils import get_offset, non_zero_range, verify_series
|
||||
|
||||
def stochrsi(close, length=None, rsi_length=None, k=None, d=None, offset=None, **kwargs):
|
||||
"""Indicator: Stochastic RSI Oscillator (STOCHRSI)"""
|
||||
# Validate arguments
|
||||
close = verify_series(close)
|
||||
length = length if length and length > 0 else 14
|
||||
rsi_length = rsi_length if rsi_length and rsi_length > 0 else 14
|
||||
k = k if k and k > 0 else 3
|
||||
d = d if d and d > 0 else 3
|
||||
offset = get_offset(offset)
|
||||
|
||||
# Calculate Result
|
||||
rsi_ = rsi(close, length=rsi_length)
|
||||
lowest_rsi = rsi_.rolling(length).min()
|
||||
highest_rsi = rsi_.rolling(length).max()
|
||||
|
||||
stoch = 100 * (rsi_ - lowest_rsi)
|
||||
stoch /= non_zero_range(highest_rsi, lowest_rsi)
|
||||
|
||||
stochrsi_k = sma(stoch, length=k)
|
||||
stochrsi_d = sma(stochrsi_k, length=d)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
stochrsi_k = stochrsi_k.shift(offset)
|
||||
stochrsi_d = stochrsi_d.shift(offset)
|
||||
|
||||
# Handle fills
|
||||
if "fillna" in kwargs:
|
||||
stochrsi_k.fillna(kwargs["fillna"], inplace=True)
|
||||
stochrsi_d.fillna(kwargs["fillna"], inplace=True)
|
||||
if "fill_method" in kwargs:
|
||||
stochrsi_k.fillna(method=kwargs["fill_method"], inplace=True)
|
||||
stochrsi_d.fillna(method=kwargs["fill_method"], inplace=True)
|
||||
|
||||
# Name and Categorize it
|
||||
_name = "STOCHRSI"
|
||||
_props = f"_{length}_{rsi_length}_{k}_{d}"
|
||||
stochrsi_k.name = f"{_name}k{_props}"
|
||||
stochrsi_d.name = f"{_name}d{_props}"
|
||||
stochrsi_k.category = stochrsi_d.category = "momentum"
|
||||
|
||||
# Prepare DataFrame to return
|
||||
data = {stochrsi_k.name: stochrsi_k, stochrsi_d.name: stochrsi_d}
|
||||
df = DataFrame(data)
|
||||
df.name = f"{_name}{_props}"
|
||||
df.category = stochrsi_k.category
|
||||
|
||||
return df
|
||||
|
||||
|
||||
|
||||
stochrsi.__doc__ = \
|
||||
"""Stochastic (STOCHRSI)
|
||||
|
||||
|
||||
"Stochastic RSI and Dynamic Momentum Index" was created by Tushar Chande and Stanley Kroll and published in Stock & Commodities V.11:5 (189-199)
|
||||
|
||||
It is a range-bound oscillator with two lines moving between 0 and 100.
|
||||
The first line (%K) displays the current RSI in relation to the period's
|
||||
high/low range. The second line (%D) is a Simple Moving Average of the %K line.
|
||||
The most common choices are a 14 period %K and a 3 period SMA for %D.
|
||||
|
||||
Sources:
|
||||
https://www.tradingview.com/wiki/Stochastic_(STOCH)
|
||||
|
||||
Calculation:
|
||||
Default Inputs:
|
||||
length=14, rsi_length=14, k=3, d=3
|
||||
RSI = Relative Strength Index
|
||||
SMA = Simple Moving Average
|
||||
|
||||
RSI = RSI(high, low, close, rsi_length)
|
||||
LL = lowest RSI for last rsi_length periods
|
||||
HH = highest RSI for last rsi_length periods
|
||||
|
||||
STOCHRSI = 100 * (RSI - LL) / (HH - LL)
|
||||
STOCHRSIk = SMA(STOCHRSI, k)
|
||||
STOCHRSId = SMA(STOCHRSIk, d)
|
||||
|
||||
Args:
|
||||
high (pd.Series): Series of 'high's
|
||||
low (pd.Series): Series of 'low's
|
||||
close (pd.Series): Series of 'close's
|
||||
length (int): The STOCHRSI period. Default: 14
|
||||
rsi_length (int): RSI period. Default: 14
|
||||
k (int): The Fast %K period. Default: 3
|
||||
d (int): The Slow %K period. Default: 3
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
fill_method (value, optional): Type of fill method
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: RSI %K, RSI %D columns.
|
||||
"""
|
||||
+1
-1
@@ -19,6 +19,6 @@ sample_data = read_csv(
|
||||
|
||||
def error_analysis(df, kind, msg, icon=INFO, newline=True):
|
||||
if VERBOSE:
|
||||
s = f" {icon} {df.name}['{kind}']: {msg}"
|
||||
s = f"{icon} {df.name}['{kind}']: {msg}"
|
||||
if newline: s = f"\n{s}"
|
||||
print(s)
|
||||
@@ -335,45 +335,19 @@ class TestMomentum(TestCase):
|
||||
self.assertIsInstance(result, DataFrame)
|
||||
self.assertEqual(result.name, "SQZhlr_20_2.0_20_1.5_LB")
|
||||
|
||||
# @skip
|
||||
def test_stoch(self):
|
||||
result = pandas_ta.stoch(self.high, self.low, self.close, fast_k=14, slow_k=14, slow_d=14)
|
||||
self.assertIsInstance(result, DataFrame)
|
||||
self.assertEqual(result.name, "STOCH_14_14_14")
|
||||
self.assertEqual(len(result.columns), 4)
|
||||
|
||||
# TV Correlation
|
||||
result = pandas_ta.stoch(self.high, self.low, self.close)
|
||||
self.assertIsInstance(result, DataFrame)
|
||||
self.assertEqual(result.name, "STOCH_14_5_3")
|
||||
self.assertEqual(result.name, "STOCH_14_3_3")
|
||||
|
||||
try:
|
||||
tal_stochf = tal.STOCHF(self.high, self.low, self.close)
|
||||
tal_stoch = tal.STOCH(self.high, self.low, self.close)
|
||||
tal_stochdf = DataFrame({"STOCHF_14": tal_stochf[0], "STOCHF_3": tal_stochf[1], "STOCH_5": tal_stoch[0], "STOCH_3": tal_stoch[1]})
|
||||
pdt.assert_frame_equal(result, tal_stochdf)
|
||||
except AssertionError as ae:
|
||||
try:
|
||||
stochfk_corr = pandas_ta.utils.df_error_analysis(result.iloc[:,0], tal_stochdf.iloc[:,0], col=CORRELATION)
|
||||
self.assertGreater(stochfk_corr, CORRELATION_THRESHOLD)
|
||||
except Exception as ex:
|
||||
error_analysis(result.iloc[:,0], CORRELATION, ex)
|
||||
|
||||
try:
|
||||
stochfd_corr = pandas_ta.utils.df_error_analysis(result.iloc[:,1], tal_stochdf.iloc[:,1], col=CORRELATION)
|
||||
self.assertGreater(stochfd_corr, CORRELATION_THRESHOLD)
|
||||
except Exception as ex:
|
||||
error_analysis(result.iloc[:,1], CORRELATION, ex, newline=False)
|
||||
|
||||
try:
|
||||
stochsk_corr = pandas_ta.utils.df_error_analysis(result.iloc[:,2], tal_stochdf.iloc[:,2], col=CORRELATION)
|
||||
self.assertGreater(stochsk_corr, CORRELATION_THRESHOLD)
|
||||
except Exception as ex:
|
||||
error_analysis(result.iloc[:,2], CORRELATION, ex, newline=False)
|
||||
|
||||
try:
|
||||
stochsd_corr = pandas_ta.utils.df_error_analysis(result.iloc[:,3], tal_stochdf.iloc[:,3], col=CORRELATION)
|
||||
self.assertGreater(stochsd_corr, CORRELATION_THRESHOLD)
|
||||
except Exception as ex:
|
||||
error_analysis(result.iloc[:,3], CORRELATION, ex, newline=False)
|
||||
def test_stochrsi(self):
|
||||
# TV Correlation
|
||||
result = pandas_ta.stochrsi(self.close)
|
||||
self.assertIsInstance(result, DataFrame)
|
||||
self.assertEqual(result.name, "STOCHRSI_14_14_3_3")
|
||||
|
||||
def test_trix(self):
|
||||
result = pandas_ta.trix(self.close)
|
||||
|
||||
@@ -187,7 +187,12 @@ class TestMomentumExtension(TestCase):
|
||||
def test_stoch_ext(self):
|
||||
self.data.ta.stoch(append=True)
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
self.assertEqual(list(self.data.columns[-4:]), ["STOCHFk_14", "STOCHFd_3", "STOCHk_5", "STOCHd_3"])
|
||||
self.assertEqual(list(self.data.columns[-2:]), ["STOCHk_14_3_3", "STOCHd_14_3_3"])
|
||||
|
||||
def test_stochrsi_ext(self):
|
||||
self.data.ta.stochrsi(append=True)
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
self.assertEqual(list(self.data.columns[-2:]), ["STOCHRSIk_14_14_3_3", "STOCHRSId_14_14_3_3"])
|
||||
|
||||
def test_trix_ext(self):
|
||||
self.data.ta.trix(append=True)
|
||||
|
||||
@@ -10,8 +10,7 @@ from pandas import DataFrame
|
||||
class TestStrategyMethods(TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.data = sample_data.tail(210).copy()
|
||||
print(cls.data.shape)
|
||||
cls.data = sample_data
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
@@ -89,9 +88,8 @@ class TestStrategyMethods(TestCase):
|
||||
"MACD and RSI Momo with BBANDS and SMAs 50 & 200 and Cumulative Log Returns" # description
|
||||
)
|
||||
|
||||
print(self.data.shape)
|
||||
init_cols = len(self.data.columns)
|
||||
self.data.ta.strategy(custom, verbose=False, timed=True)
|
||||
self.data.ta.strategy(custom, verbose=False)
|
||||
added_cols = len(self.data.columns) - init_cols
|
||||
self.assertEqual(added_cols, 11)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user