ENH #246 td_seq added DOC updates

This commit is contained in:
Kevin Johnson
2021-03-25 12:01:16 -07:00
parent 6b3bfe252c
commit 360a26d71c
12 changed files with 177 additions and 118 deletions
+9 -22
View File
@@ -34,10 +34,11 @@ _Pandas Technical Analysis_ (**Pandas TA**) is an easy to use library that lever
* [Pandas TA Strategies](#pandas-ta-strategies)
* [Types of Strategies](#types-of-strategies)
* [DataFrame Properties](#dataframe-properties)
* [DataFrame Methods](#dataframe-methods)
* [Indicators by Category](#indicators-by-category)
* [Candles](#candles-3)
* [Cycles](#cycles-1)
* [Momentum](#momentum-36)
* [Momentum](#momentum-37)
* [Overlap](#overlap-31)
* [Performance](#performance-4)
* [Statistics](#statistics-9)
@@ -84,7 +85,7 @@ $ pip install pandas_ta
Latest Version
--------------
Best choice! Version: *0.2.53b*
Best choice! Version: *0.2.62b*
```sh
$ pip install -U git+https://github.com/twopirllc/pandas-ta
```
@@ -182,7 +183,7 @@ Thanks for using **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) | [edwardwang1](https://github.com/edwardwang1) | [ffhirata](https://github.com/ffhirata) | [FGU1](https://github.com/FGU1) | [lluissalord](https://github.com/lluissalord) | [maxdignan](https://github.com/maxdignan) | [moritzgun](https://github.com/moritzgun) | [M6stafa](https://github.com/M6stafa) | [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) | [whubsch](https://github.com/whubsch) | [witokondoria](https://github.com/witokondoria) | [wouldayajustlookatit](https://github.com/wouldayajustlookatit) | [YuvalWein](https://github.com/YuvalWein)
[alexonab](https://github.com/alexonab) | [allahyarzadeh](https://github.com/allahyarzadeh) | [codesutras](https://github.com/codesutras) | [DrPaprikaa](https://github.com/DrPaprikaa) | [daikts](https://github.com/daikts) | [dorren](https://github.com/dorren) | [edwardwang1](https://github.com/edwardwang1) | [ffhirata](https://github.com/ffhirata) | [FGU1](https://github.com/FGU1) | [lluissalord](https://github.com/lluissalord) | [M6stafa](https://github.com/M6stafa) | [maxdignan](https://github.com/maxdignan) | [moritzgun](https://github.com/moritzgun) | [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) | [whubsch](https://github.com/whubsch) | [witokondoria](https://github.com/witokondoria) | [wouldayajustlookatit](https://github.com/wouldayajustlookatit) | [YuvalWein](https://github.com/YuvalWein)
<br/>
@@ -566,7 +567,7 @@ help(ta.yf)
* _Even Better Sinewave_: **ebsw**
<br/>
### **Momentum** (36)
### **Momentum** (37)
* _Awesome Oscillator_: **ao**
* _Absolute Price Oscillator_: **apo**
@@ -601,7 +602,8 @@ help(ta.yf)
* Default is John Carter's. Enable Lazybear's with ```lazybear=True```
* _Stochastic Oscillator_: **stoch**
* _Stochastic RSI_: **stochrsi**
* _TD Sequential_: **td**
* _TD Sequential_: **td_seq**
* Excluded from ```df.ta.strategy()```.
* _Trix_: **trix**
* _True strength index_: **tsi**
* _Ultimate Oscillator_: **uo**
@@ -799,27 +801,12 @@ result = ta.cagr(df.close)
<br />
## **Breaking Indicators**
* _Bollinger Bands_ (**bbands**): New column 'bandwidth' appended to the returning DataFrame. See: ```help(ta.bbands)```
* _Volume Weighted Average Price_ (**vwap**): **Requires** the DataFrame index to be a DatetimeIndex.
## **New Indicators**
* _Arnaud Legoux Moving Average_ (**alma**) uses the curve of the Normal (Gauss) distribution to allow regulating the smoothness and high sensitivity of the indicator. See: ```help(ta.alma)```
* _Drawdown_ (**drawdown**) shows the peak-to-trough decline during a specific period for an investment,
trading account, or fund. See: ```help(ta.drawdown)```
* _Even Better Sinewave_ (**ebsw**) measures market cycles and uses a low pass filter to remove noise. See: ```help(ta.ebsw)```
* _Gann High-Low Activator_ (**hilo**) was created by Robert Krausz in a 1998. See: ```help(ta.hilo)```
* _Holt-Winter Moving Average_ (**hwma**) is a three-parameter moving average by the Holt-Winter method.
* _McGinley Dynamic_ (**mcgd**) is an overlap indicator developed by John R. McGinley, a Certified Market Technician. See: ```help(ta.mcgd)```
* _Price Volume Rank_ (**pvr**) was created by Anthony J. Macek. See: ```help(ta.pvr)```
* _Quantitative Qualitative Estimation_ (**qqe**) is like SuperTrend for a Smoothed RSI. See: ```help(ta.qqe)```
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**) 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)```
* _Tom DeMark's Sequential_ (**td_seq**) attempts to identify a price point where an uptrend or a downtrend exhausts itself and reverses. Currently exlcuded from ```df.ta.strategy()``` for performance reasons. See: ```help(ta.td_seq)```
<br/>
## **Updated Indicators**
* _ADX_ (**adx**): Added ```mamode``` with default "**RMA**" and with the same ```mamode``` options as TradingView. See ```help(ta.adx)```.
+1 -1
View File
@@ -47,7 +47,7 @@ Category = {
"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",
"slope", "smi", "squeeze", "stoch", "stochrsi", "td_seq", "trix", "tsi", "uo",
"willr"
],
# Overlap
+27 -14
View File
@@ -607,21 +607,30 @@ class AnalysisIndicators(BasePandasObject):
"""Strategy Method
An experimental method that by default runs all applicable indicators.
Future implementations will allow more specific indicator generation through
a json config file.
Future implementations will allow more specific indicator generation
with possibly as json, yaml config file or an sqlite3 table.
Args:
name (str, optional): Default: "all"
exclude (list, optional): Default: []. List of indicator names to exclude.
kwargs:
(optional) Default: {}. Any indicator argument you want to modify.
For example, length=20 or offset=-1 or high=df["high"] ...
Kwargs:
chunksize (bool): Adjust the chunksize for the Multiprocessing Pool.
Default: Number of cores of the OS
exclude (list): List of indicator names to exclude. Some are
excluded by default for various reasons; they require additional
sources, performance (td_seq), not a ohlcv chart (vp) etc.
name (str): Select all indicators or indicators by
Category such as: "candles", "cycles", "momentum", "overlap",
"performance", "statistics", "trend", "volatility", "volume", or
"all". Default: "all"
ordered (bool): Whether to run "all" in order. Default: True
timed (bool): Show the process time of the strategy().
Default: False
verbose (bool): Provide some additional insight on the progress of
the strategy() execution. Default: False
"""
# cpus = cpu_count()
# Ensure indicators are appended to the DataFrame
kwargs["append"] = True
all_ordered = kwargs.pop("ordered", False)
all_ordered = kwargs.pop("ordered", True)
mp_chunksize = kwargs.pop("chunksize", self.cores)
# Initialize
@@ -637,6 +646,7 @@ class AnalysisIndicators(BasePandasObject):
"long_run",
"short_run",
"trend_return",
"td_seq", # Performance exclusion
"vp",
]
@@ -702,7 +712,7 @@ class AnalysisIndicators(BasePandasObject):
# Some magic to optimize chunksize for speed based on total ta indicators
_chunksize = mp_chunksize - 1 if mp_chunksize > _total_ta else int(npLog10(_total_ta)) + 1
if verbose:
print(f"[i] Multiprocessing {_total_ta} indicators with {_chunksize} chunks over {self.cores}/{cpu_count()} cpus.")
print(f"[i] Multiprocessing {_total_ta} indicators with {_chunksize} chunks and {self.cores}/{cpu_count()} cpus.")
results = None
if mode["custom"]:
@@ -810,7 +820,11 @@ class AnalysisIndicators(BasePandasObject):
elif df.empty:
print(f"[X] DataFrame is empty: {df.shape}")
return
else: self._df = df
else:
if kwargs.pop("lc_input", False):
df.index.name = df.index.name.lower()
df.columns = df.columns.str.lower()
self._df = df
if strategy is not None: self.strategy(strategy, **kwargs)
return df
@@ -1043,10 +1057,9 @@ class AnalysisIndicators(BasePandasObject):
result = stochrsi(high=high, low=low, close=close, length=length, rsi_length=rsi_length, k=k, d=d, offset=offset, **kwargs)
return self._post_process(result, **kwargs)
def td(self, offset=None, show_all=True, **kwargs):
def td_seq(self, asint=None, offset=None, show_all=None, **kwargs):
close = self._get_column(kwargs.pop("close", "close"))
result = td(close=close, offset=offset, show_all=show_all, **kwargs)
result = td_seq(close=close, asint=asint, offset=offset, show_all=show_all, **kwargs)
return self._post_process(result, **kwargs)
def trix(self, length=None, signal=None, scalar=None, drift=None, offset=None, **kwargs):
+1 -1
View File
@@ -31,7 +31,7 @@ from .smi import smi
from .squeeze import squeeze
from .stoch import stoch
from .stochrsi import stochrsi
from .td import td
from .td_seq import td_seq
from .trix import trix
from .tsi import tsi
from .uo import uo
-67
View File
@@ -1,67 +0,0 @@
# -*- coding: utf-8 -*-
import numpy as np
from pandas import DataFrame, Series
from pandas_ta.utils import get_offset, verify_series
def true_sequence_count(s):
index = s.where(s == False).last_valid_index()
if index is None:
return s.count()
else:
s = s[s.index > index]
return s.count()
def calc_td(close, direction, show_all):
td_bool = close.diff(4) > 0 if direction=='up' else close.diff(4) < 0
td_num = np.where(td_bool, td_bool.rolling(13, min_periods=0).apply(true_sequence_count), 0)
td_num = Series(td_num)
if show_all:
td_num = td_num.mask(td_num == 0)
else:
td_num = td_num.mask(~td_num.between(6,9))
return td_num
def td(close, offset=None, show_all=True, **kwargs):
up = calc_td(close, 'up', show_all)
down = calc_td(close, 'down', show_all)
df = DataFrame({'TD_up': up, 'TD_down': down})
# Offset
if offset and offset != 0:
df = df.shift(offset)
if "fillna" in kwargs:
df.fillna(kwargs["fillna"], inplace=True)
# Name & Category
df.name = "TD"
df.category = "momentum"
return df
td.__doc__ = \
"""TD Sequential (TD)
TD Sequential indicator.
Sources:
https://tradetrekker.wordpress.com/tdsequential/
Calculation:
compare current close price with 4 days ago price, up to 13 days.
for the consecutive ascending or descending price sequence, display 6th to 9th day value.
Args:
close (pd.Series): Series of 'close's
offset (int): How many periods to offset the result. Default: 0
show_all (bool): default True, show 1 - 13. If set to false, only show 6 - 9
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
Returns:
pd.DataFrame: New feature generated.
"""
+105
View File
@@ -0,0 +1,105 @@
# -*- coding: utf-8 -*-
# import numpy as np
from numpy import where as npWhere
from pandas import DataFrame, Series
from pandas_ta.utils import get_offset, verify_series
def td_seq(close, asint=None, offset=None, **kwargs):
"""Indicator: Tom Demark Sequential (TD_SEQ)"""
# Validate arguments
close = verify_series(close)
offset = get_offset(offset)
asint = asint if isinstance(asint, bool) else False
show_all = kwargs.setdefault("show_all", True)
def true_sequence_count(series: Series):
index = series.where(series == False).last_valid_index()
if index is None:
return series.count()
else:
s = series[series.index > index]
return s.count()
def calc_td(series: Series, direction: str, show_all: bool):
td_bool = series.diff(4) > 0 if direction=="up" else series.diff(4) < 0
td_num = npWhere(
td_bool, td_bool.rolling(13, min_periods=0).apply(true_sequence_count), 0
)
td_num = Series(td_num)
if show_all:
td_num = td_num.mask(td_num == 0)
else:
td_num = td_num.mask(~td_num.between(6,9))
return td_num
up_seq = calc_td(close, "up", show_all)
down_seq = calc_td(close, "down", show_all)
if asint:
if up_seq.hasnans and down_seq.hasnans:
up_seq.fillna(0, inplace=True)
down_seq.fillna(0, inplace=True)
up_seq = up_seq.astype(int)
down_seq = down_seq.astype(int)
# Offset
if offset != 0:
up_seq = up_seq.shift(offset)
down_seq = down_seq.shift(offset)
# Handle fills
if "fillna" in kwargs:
up_seq.fillna(kwargs["fillna"], inplace=True)
down_seq.fillna(kwargs["fillna"], inplace=True)
if "fill_method" in kwargs:
up_seq.fillna(method=kwargs["fill_method"], inplace=True)
down_seq.fillna(method=kwargs["fill_method"], inplace=True)
# Name & Category
up_seq.name = f"TD_SEQ_UPa" if show_all else f"TD_SEQ_UP"
down_seq.name = f"TD_SEQ_DNa" if show_all else f"TD_SEQ_DN"
up_seq.category = down_seq.category = "momentum"
# Prepare Dataframe to return
data = {
up_seq.name: up_seq,
down_seq.name: down_seq
}
df = DataFrame(data)
df.name = "TD_SEQ"
df.category = up_seq.category
return df
td_seq.__doc__ = \
"""TD Sequential (TD_SEQ)
Tom DeMark's Sequential indicator attempts to identify a price point where an
uptrend or a downtrend exhausts itself and reverses.
Sources:
https://tradetrekker.wordpress.com/tdsequential/
Calculation:
Compare current close price with 4 days ago price, up to 13 days. For the
consecutive ascending or descending price sequence, display 6th to 9th day
value.
Args:
close (pd.Series): Series of 'close's
asint (bool): If True, fillnas with 0 and change type to int. Default: False
offset (int): How many periods to offset the result. Default: 0
Kwargs:
show_all (bool): Show 1 - 13. If set to False, show 6 - 9. Default: True
fillna (value, optional): pd.DataFrame.fillna(value)
Returns:
pd.DataFrame: New feature generated.
"""
+3 -4
View File
@@ -57,10 +57,9 @@ def cksp(high, low, close, p=None, x=None, q=None, offset=None, **kwargs):
cksp.__doc__ = \
"""Chande Kroll Stop (CKSP)
The Tushar Chande and Stanley Kroll in their book
“The New Technical Trader”. It is a trend-following indicator,
identifying your stop by calculating the average true range of
the recent market volatility.
The Tushar Chande and Stanley Kroll in their book “The New Technical Trader”.
It is a trend-following indicator, identifying your stop by calculating the
average true range of the recent market volatility.
Sources:
https://www.multicharts.com/discussion/viewtopic.php?t=48914
+1 -1
View File
@@ -57,7 +57,7 @@ def fibonacci(n: int = 2, **kwargs: dict) -> npNdArray:
a, b = 1, 1
result = npArray([a])
for i in range(0, n):
for _ in range(0, n):
a, b = b, a + b
result = npAppend(result, a)
+1 -1
View File
@@ -18,7 +18,7 @@ setup(
"pandas_ta.volatility",
"pandas_ta.volume"
],
version=".".join(("0", "2", "61b")),
version=".".join(("0", "2", "62b")),
description=long_description,
long_description=long_description,
author="Kevin Johnson",
+7 -3
View File
@@ -207,10 +207,14 @@ class TestMomentumExtension(TestCase):
self.assertIsInstance(self.data, DataFrame)
self.assertEqual(list(self.data.columns[-2:]), ["STOCHRSIk_14_14_3_3", "STOCHRSId_14_14_3_3"])
def test_td_ext(self):
self.data.ta.td(append=True)
def test_td_seq_ext(self):
self.data.ta.td_seq(show_all=False, append=True)
self.assertIsInstance(self.data, DataFrame)
self.assertEqual(list(self.data.columns[-2:]), ["TD_up", "TD_down"])
self.assertEqual(list(self.data.columns[-2:]), ["TD_SEQ_UP", "TD_SEQ_DN"])
self.data.ta.td_seq(show_all=True, append=True)
self.assertIsInstance(self.data, DataFrame)
self.assertEqual(list(self.data.columns[-2:]), ["TD_SEQ_UPa", "TD_SEQ_DNa"])
def test_trix_ext(self):
self.data.ta.trix(append=True)
+3 -4
View File
@@ -362,11 +362,10 @@ class TestMomentum(TestCase):
self.assertIsInstance(result, DataFrame)
self.assertEqual(result.name, "STOCHRSI_14_14_3_3")
def test_td(self):
# TD Sequential
result = pandas_ta.td(self.close)
def test_td_seq(self):
result = pandas_ta.td_seq(self.close)
self.assertIsInstance(result, DataFrame)
self.assertEqual(result.name, "TD")
self.assertEqual(result.name, "TD_SEQ")
def test_trix(self):
result = pandas_ta.trix(self.close)
+19
View File
@@ -165,6 +165,25 @@ class TestStrategyMethods(TestCase):
)
self.data.ta.strategy(custom, verbose=verbose, timed=strategy_timed)
# @skip
def test_custom_a(self):
self.category = "Custom E"
amat_logret_ta = [
{"kind": "amat", "fast": 20, "slow": 50 }, # 2
{"kind": "log_return", "cumulative": True}, # 1
{"kind": "ema", "close": "CUMLOGRET_1", "length": 5} # 1
]
custom = pandas_ta.Strategy(
"AMAT Log Returns", # name
amat_logret_ta, # ta
"AMAT Log Returns", # description
)
self.data.ta.strategy(custom, verbose=verbose, timed=strategy_timed, ordered=True)
self.data.ta.trend_return(trend=self.data["AMATe_LR_2"], cumulative=True, append=True)
self.assertEqual(len(self.data.columns), 13)
# @skip
def test_momentum_category(self):
self.category = "Momentum"