From 99973f36110a8e6c44564f58bea5b069bbe9ba13 Mon Sep 17 00:00:00 2001 From: James Sawyer Date: Thu, 1 Oct 2020 16:18:01 +0100 Subject: [PATCH] formatting fixes, PEP8 etc --- docs/conf.py | 70 +- examples/watchlist.py | 52 +- pandas_ta/__init__.py | 164 ++- pandas_ta/candles/__init__.py | 2 +- pandas_ta/candles/cdl_doji.py | 17 +- pandas_ta/candles/cdl_inside.py | 53 +- pandas_ta/candles/ha.py | 7 +- pandas_ta/core.py | 1710 +++++++++++++++++------ pandas_ta/momentum/ao.py | 20 +- pandas_ta/momentum/apo.py | 18 +- pandas_ta/momentum/bias.py | 29 +- pandas_ta/momentum/bop.py | 7 +- pandas_ta/momentum/brar.py | 37 +- pandas_ta/momentum/cci.py | 17 +- pandas_ta/momentum/cfo.py | 9 +- pandas_ta/momentum/cg.py | 15 +- pandas_ta/momentum/cmo.py | 7 +- pandas_ta/momentum/coppock.py | 20 +- pandas_ta/momentum/er.py | 37 +- pandas_ta/momentum/eri.py | 21 +- pandas_ta/momentum/fisher.py | 13 +- pandas_ta/momentum/inertia.py | 50 +- pandas_ta/momentum/kdj.py | 38 +- pandas_ta/momentum/kst.py | 35 +- pandas_ta/momentum/macd.py | 9 +- pandas_ta/momentum/mom.py | 17 +- pandas_ta/momentum/pgo.py | 15 +- pandas_ta/momentum/ppo.py | 34 +- pandas_ta/momentum/psl.py | 27 +- pandas_ta/momentum/pvo.py | 29 +- pandas_ta/momentum/roc.py | 20 +- pandas_ta/momentum/rsi.py | 9 +- pandas_ta/momentum/rvgi.py | 32 +- pandas_ta/momentum/slope.py | 20 +- pandas_ta/momentum/smi.py | 15 +- pandas_ta/momentum/squeeze.py | 41 +- pandas_ta/momentum/stoch.py | 20 +- pandas_ta/momentum/stochrsi.py | 19 +- pandas_ta/momentum/trix.py | 30 +- pandas_ta/momentum/tsi.py | 15 +- pandas_ta/momentum/uo.py | 47 +- pandas_ta/momentum/willr.py | 10 +- pandas_ta/overlap/__init__.py | 2 +- pandas_ta/overlap/dema.py | 7 +- pandas_ta/overlap/ema.py | 15 +- pandas_ta/overlap/fwma.py | 19 +- pandas_ta/overlap/hilo.py | 31 +- pandas_ta/overlap/hl2.py | 5 +- pandas_ta/overlap/hlc3.py | 7 +- pandas_ta/overlap/hma.py | 12 +- pandas_ta/overlap/ichimoku.py | 52 +- pandas_ta/overlap/kama.py | 18 +- pandas_ta/overlap/linreg.py | 29 +- pandas_ta/overlap/midpoint.py | 16 +- pandas_ta/overlap/midprice.py | 16 +- pandas_ta/overlap/ohlc4.py | 5 +- pandas_ta/overlap/pwma.py | 15 +- pandas_ta/overlap/rma.py | 7 +- pandas_ta/overlap/sinwma.py | 15 +- pandas_ta/overlap/sma.py | 20 +- pandas_ta/overlap/supertrend.py | 30 +- pandas_ta/overlap/swma.py | 17 +- pandas_ta/overlap/t3.py | 20 +- pandas_ta/overlap/tema.py | 12 +- pandas_ta/overlap/trima.py | 12 +- pandas_ta/overlap/vwap.py | 9 +- pandas_ta/overlap/vwma.py | 9 +- pandas_ta/overlap/wcp.py | 9 +- pandas_ta/overlap/wma.py | 12 +- pandas_ta/overlap/zlma.py | 22 +- pandas_ta/performance/__init__.py | 2 +- pandas_ta/performance/log_return.py | 9 +- pandas_ta/performance/percent_return.py | 7 +- pandas_ta/performance/trend_return.py | 37 +- pandas_ta/statistics/__init__.py | 2 +- pandas_ta/statistics/entropy.py | 11 +- pandas_ta/statistics/kurtosis.py | 10 +- pandas_ta/statistics/mad.py | 10 +- pandas_ta/statistics/median.py | 10 +- pandas_ta/statistics/quantile.py | 10 +- pandas_ta/statistics/skew.py | 20 +- pandas_ta/statistics/stdev.py | 11 +- pandas_ta/statistics/variance.py | 14 +- pandas_ta/statistics/zscore.py | 7 +- pandas_ta/trend/adx.py | 24 +- pandas_ta/trend/amat.py | 14 +- pandas_ta/trend/aroon.py | 24 +- pandas_ta/trend/chop.py | 22 +- pandas_ta/trend/cksp.py | 7 +- pandas_ta/trend/decay.py | 11 +- pandas_ta/trend/decreasing.py | 7 +- pandas_ta/trend/dpo.py | 11 +- pandas_ta/trend/increasing.py | 7 +- pandas_ta/trend/long_run.py | 9 +- pandas_ta/trend/psar.py | 9 +- pandas_ta/trend/qstick.py | 22 +- pandas_ta/trend/short_run.py | 9 +- pandas_ta/trend/ttm_trend.py | 5 +- pandas_ta/trend/vortex.py | 10 +- pandas_ta/utils/__init__.py | 2 +- pandas_ta/utils/_candles.py | 4 +- pandas_ta/utils/_core.py | 19 +- pandas_ta/utils/_math.py | 30 +- pandas_ta/utils/_signals.py | 171 ++- pandas_ta/utils/_time.py | 7 +- pandas_ta/volatility/__init__.py | 2 +- pandas_ta/volatility/aberration.py | 22 +- pandas_ta/volatility/accbands.py | 30 +- pandas_ta/volatility/atr.py | 16 +- pandas_ta/volatility/bbands.py | 11 +- pandas_ta/volatility/donchian.py | 30 +- pandas_ta/volatility/kc.py | 17 +- pandas_ta/volatility/massi.py | 10 +- pandas_ta/volatility/natr.py | 30 +- pandas_ta/volatility/pdist.py | 7 +- pandas_ta/volatility/rvi.py | 32 +- pandas_ta/volatility/true_range.py | 9 +- pandas_ta/volatility/ui.py | 6 +- pandas_ta/volume/__init__.py | 2 +- pandas_ta/volume/ad.py | 9 +- pandas_ta/volume/adosc.py | 19 +- pandas_ta/volume/aobv.py | 19 +- pandas_ta/volume/cmf.py | 23 +- pandas_ta/volume/efi.py | 15 +- pandas_ta/volume/eom.py | 24 +- pandas_ta/volume/mfi.py | 20 +- pandas_ta/volume/nvi.py | 12 +- pandas_ta/volume/obv.py | 7 +- pandas_ta/volume/pvi.py | 12 +- pandas_ta/volume/pvol.py | 7 +- pandas_ta/volume/pvt.py | 7 +- pandas_ta/volume/vp.py | 8 +- setup.py | 44 +- tests/config.py | 23 +- tests/context.py | 6 +- tests/test_ext_indicator_candle.py | 11 +- tests/test_ext_indicator_momentum.py | 62 +- tests/test_ext_indicator_overlap_ext.py | 23 +- tests/test_ext_indicator_performance.py | 33 +- tests/test_ext_indicator_statistics.py | 8 +- tests/test_ext_indicator_trend.py | 31 +- tests/test_ext_indicator_volatility.py | 27 +- tests/test_ext_indicator_volume.py | 23 +- tests/test_indicator_candle.py | 38 +- tests/test_indicator_momentum.py | 114 +- tests/test_indicator_overlap.py | 84 +- tests/test_indicator_performance.py | 46 +- tests/test_indicator_statistics.py | 32 +- tests/test_indicator_trend.py | 60 +- tests/test_indicator_volatility.py | 76 +- tests/test_indicator_volume.py | 42 +- tests/test_strategy.py | 137 +- tests/test_utils.py | 129 +- 153 files changed, 3599 insertions(+), 1740 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 23e9cfd..f0f2ec5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -16,18 +16,16 @@ # import sys # sys.path.insert(0, os.path.abspath('.')) - # -- Project information ----------------------------------------------------- -project = 'pandas_ta' -copyright = '2019, Kevin Johnson' -author = 'Kevin Johnson' +project = "pandas_ta" +copyright = "2019, Kevin Johnson" +author = "Kevin Johnson" # The short X.Y version -version = '0.0.1' +version = "0.0.1" # The full version, including alpha/beta/rc tags -release = 'alpha' - +release = "alpha" # -- General configuration --------------------------------------------------- @@ -39,22 +37,22 @@ release = 'alpha' # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.todo', - 'sphinx.ext.mathjax', - 'sphinx.ext.viewcode', + "sphinx.ext.todo", + "sphinx.ext.mathjax", + "sphinx.ext.viewcode", ] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -66,18 +64,17 @@ language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The name of the Pygments (syntax highlighting) style to use. pygments_style = None - # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'alabaster' +html_theme = "alabaster" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -88,7 +85,7 @@ html_theme = 'alabaster' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Custom sidebar templates, must be a dictionary that maps document names # to template names. @@ -100,12 +97,10 @@ html_static_path = ['_static'] # # html_sidebars = {} - # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. -htmlhelp_basename = 'pandas_tadoc' - +htmlhelp_basename = "pandas_tadoc" # -- Options for LaTeX output ------------------------------------------------ @@ -113,15 +108,12 @@ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # # 'preamble': '', - # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -131,20 +123,20 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'pandas_ta.tex', 'pandas\\_ta Documentation', - 'Kevin Johnson', 'manual'), + ( + master_doc, + "pandas_ta.tex", + "pandas\\_ta Documentation", + "Kevin Johnson", + "manual", + ), ] - # -- Options for manual page output ------------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'pandas_ta', 'pandas_ta Documentation', - [author], 1) -] - +man_pages = [(master_doc, "pandas_ta", "pandas_ta Documentation", [author], 1)] # -- Options for Texinfo output ---------------------------------------------- @@ -152,12 +144,17 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'pandas_ta', 'pandas_ta Documentation', - author, 'pandas_ta', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "pandas_ta", + "pandas_ta Documentation", + author, + "pandas_ta", + "One line description of project.", + "Miscellaneous", + ), ] - # -- Options for Epub output ------------------------------------------------- # Bibliographic Dublin Core info. @@ -173,8 +170,7 @@ epub_title = project # epub_uid = '' # A list of files that should not be packed into the epub file. -epub_exclude_files = ['search.html'] - +epub_exclude_files = ["search.html"] # -- Extension configuration ------------------------------------------------- diff --git a/examples/watchlist.py b/examples/watchlist.py index fcd157a..23448a6 100644 --- a/examples/watchlist.py +++ b/examples/watchlist.py @@ -4,12 +4,13 @@ import datetime as dt from pathlib import Path from random import random -import pandas as pd # pip install pandas +import pandas as pd # pip install pandas import yfinance as yf + # yf.pdr_override() # <== that's all it takes :-) -import alphaVantageAPI as AV # pip install alphaVantage-api -import pandas_ta as ta # pip install pandas_ta +import alphaVantageAPI as AV # pip install alphaVantage-api +import pandas_ta as ta # pip install pandas_ta def colors(colors: str = None, default: str = "GrRd"): @@ -17,17 +18,14 @@ def colors(colors: str = None, default: str = "GrRd"): # Pairs "GrRd": ["green", "red"], "RdGr": ["red", "green"], - "BkGy": ["black", "gray"], "BkSv": ["black", "silver"], "BkPr": ["black", "purple"], "BkBl": ["black", "blue"], - "GyBk": ["gray", "black"], "GySv": ["gray", "silver"], "GyPr": ["gray", "purple"], "GyBl": ["gray", "blue"], - "SvGy": ["silver", "gray"], "FcLi": ["fuchsia", "lime"], # Triples @@ -69,6 +67,7 @@ class Watchlist(object): ## Required Arguments: - tickers: A list of strings containing tickers. Example: ["SPY", "AAPL"] """ + def __init__( self, tickers: list, @@ -76,14 +75,15 @@ class Watchlist(object): name: str = None, strategy: ta.Strategy = None, ds: object = None, - **kwargs + **kwargs, ): self.verbose = kwargs.pop("verbose", False) self.debug = kwargs.pop("debug", False) self.tickers = tickers self.tf = tf - self.name = name if isinstance(name, str) else f"Watch: {', '.join(tickers)}" + self.name = name if isinstance(name, + str) else f"Watch: {', '.join(tickers)}" self.data = None self.kwargs = kwargs self.strategy = strategy @@ -96,12 +96,23 @@ class Watchlist(object): elif isinstance(ds, str) and ds.lower() == "yahoo": self.ds = yf else: - AVkwargs = {"api_key": "YOUR API KEY", "clean": True, "export": True, "export_path": ".", "output_size": "full", "premium": False} + AVkwargs = { + "api_key": "YOUR API KEY", + "clean": True, + "export": True, + "export_path": ".", + "output_size": "full", + "premium": False, + } self.av_kwargs = self.kwargs.pop("av_kwargs", AVkwargs) self.file_path = self.av_kwargs["export_path"] self.ds = AV.AlphaVantage(**self.av_kwargs) - def _drop_columns(self, df: pd.DataFrame, cols: list = ["Unnamed: 0", "date", "split_coefficient", "dividend"]): + def _drop_columns( + self, + df: pd.DataFrame, + cols: list = ["Unnamed: 0", "date", "split_coefficient", "dividend"], + ): """Helper methods to drop columns silently.""" df_columns = list(df.columns) if any(_ in df_columns for _ in cols): @@ -113,8 +124,11 @@ class Watchlist(object): def _load_all(self, **kwargs) -> dict: """Updates the Watchlist's data property with a dictionary of DataFrames keyed by ticker.""" - if self.tickers is not None and isinstance(self.tickers, list) and len(self.tickers): - self.data = {ticker: self.load(ticker, **kwargs) for ticker in self.tickers} + if (self.tickers is not None and isinstance(self.tickers, list) and + len(self.tickers)): + self.data = { + ticker: self.load(ticker, **kwargs) for ticker in self.tickers + } return self.data def load( @@ -123,7 +137,7 @@ class Watchlist(object): tf: str = None, index: str = "date", drop: list = ["dividend", "split_coefficient"], - **kwargs + **kwargs, ) -> pd.DataFrame: """Loads or Downloads (if a local csv does not exist) the data from the Data Source. When successful, it returns a Data Frame for the requested @@ -163,10 +177,11 @@ class Watchlist(object): df = self._drop_columns(df) if kwargs.pop("analyze", True): - if self.debug: print(f"[+] TA[{len(self.strategy.ta)}]: {self.strategy.name}") + if self.debug: + print(f"[+] TA[{len(self.strategy.ta)}]: {self.strategy.name}") df.ta.strategy(self.strategy, **kwargs) - df.ticker = ticker # Attach ticker to the DataFrame + df.ticker = ticker # Attach ticker to the DataFrame return df @property @@ -178,7 +193,8 @@ class Watchlist(object): def data(self, value: dict) -> None: # Later check dict has string keys and DataFrame values if value is not None and isinstance(value, dict): - if self.verbose: print(f"[+] New data") + if self.verbose: + print(f"[+] New data") self._data = value else: self._data = None @@ -205,7 +221,7 @@ class Watchlist(object): if value is not None and isinstance(value, ta.Strategy): self._strategy = value else: - self._strategy = ta.CommonStrategy + self._strategy = ta.CommonStrategy @property def tf(self) -> str: @@ -262,4 +278,4 @@ class Watchlist(object): if self.data is not None: s += f", data[{len(self.data.keys())}])" return s - return s + ")" \ No newline at end of file + return s + ")" diff --git a/pandas_ta/__init__.py b/pandas_ta/__init__.py index 03f06b7..2da5797 100644 --- a/pandas_ta/__init__.py +++ b/pandas_ta/__init__.py @@ -19,6 +19,7 @@ else: __version__ = _dist.version from importlib.util import find_spec + Imports = { "scipy": find_spec("scipy") is not None, "sklearn": find_spec("sklearn") is not None, @@ -26,7 +27,7 @@ Imports = { "mplfinance": find_spec("mplfinance") is not None, "alphaVantage-api ": find_spec("alphaVantageAPI") is not None, "yfinance": find_spec("yfinance") is not None, - "talib": find_spec("talib") is not None + "talib": find_spec("talib") is not None, } # Not ideal and not dynamic but it works. @@ -34,43 +35,160 @@ Imports = { Category = { # Candles "candles": ["cdl_doji", "cdl_inside", "ha"], - # Momentum - "momentum": ["ao", "apo", "bias", "bop", "brar", "cci", "cfo", "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"], - + "momentum": [ + "ao", + "apo", + "bias", + "bop", + "brar", + "cci", + "cfo", + "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"], - + "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", + ], # Performance "performance": ["log_return", "percent_return", "trend_return"], - # Statistics - "statistics": ["entropy", "kurtosis", "mad", "median", "quantile", "skew", "stdev", "variance", "zscore"], - + "statistics": [ + "entropy", + "kurtosis", + "mad", + "median", + "quantile", + "skew", + "stdev", + "variance", + "zscore", + ], # Trend - "trend": ["adx", "amat", "aroon", "chop", "cksp", "decay", "decreasing", "dpo", "increasing", "long_run", "psar", "qstick", "short_run", "ttm_trend", "vortex"], - + "trend": [ + "adx", + "amat", + "aroon", + "chop", + "cksp", + "decay", + "decreasing", + "dpo", + "increasing", + "long_run", + "psar", + "qstick", + "short_run", + "ttm_trend", + "vortex", + ], # Volatility - "volatility": ["aberration", "accbands", "atr", "bbands", "donchian", "kc", "massi", "natr", "pdist", "rvi", "true_range", "ui"], - + "volatility": [ + "aberration", + "accbands", + "atr", + "bbands", + "donchian", + "kc", + "massi", + "natr", + "pdist", + "rvi", + "true_range", + "ui", + ], # Volume, "vp" or "Volume Profile" is unique - "volume": ["ad", "adosc", "aobv", "cmf", "efi", "eom", "mfi", "nvi", "obv", "pvi", "pvol", "pvt"], + "volume": [ + "ad", + "adosc", + "aobv", + "cmf", + "efi", + "eom", + "mfi", + "nvi", + "obv", + "pvi", + "pvol", + "pvt", + ], } # https://www.worldtimezone.com/markets24.php EXCHANGE_TZ = { - "NZSX": 12, "ASX": 11, - "TSE": 9, "HKE": 8, "SSE": 8, "SGX": 8, - "NSE": 5.5, "DIFX": 4, "RTS": 3, - "JSE": 2, "FWB": 1, "LSE": 1, - "BMF": -2, "NYSE": -4, "TSX": -4 + "NZSX": 12, + "ASX": 11, + "TSE": 9, + "HKE": 8, + "SSE": 8, + "SGX": 8, + "NSE": 5.5, + "DIFX": 4, + "RTS": 3, + "JSE": 2, + "FWB": 1, + "LSE": 1, + "BMF": -2, + "NYSE": -4, + "TSX": -4, } RATE = { - "TRADING_DAYS_PER_YEAR": 252, # Keep even + "TRADING_DAYS_PER_YEAR": 252, # Keep even "TRADING_HOURS_PER_DAY": 6.5, - "MINUTES_PER_HOUR": 60 + "MINUTES_PER_HOUR": 60, } - -from pandas_ta.core import * \ No newline at end of file +from pandas_ta.core import * diff --git a/pandas_ta/candles/__init__.py b/pandas_ta/candles/__init__.py index 1657062..a94f3f7 100644 --- a/pandas_ta/candles/__init__.py +++ b/pandas_ta/candles/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- from .ha import ha from .cdl_doji import cdl_doji -from .cdl_inside import cdl_inside \ No newline at end of file +from .cdl_inside import cdl_inside diff --git a/pandas_ta/candles/cdl_doji.py b/pandas_ta/candles/cdl_doji.py index 109d1b9..6ec4e08 100644 --- a/pandas_ta/candles/cdl_doji.py +++ b/pandas_ta/candles/cdl_doji.py @@ -3,7 +3,19 @@ from pandas_ta.overlap import sma from pandas_ta.utils import get_offset, high_low_range, is_percent from pandas_ta.utils import non_zero_range, real_body, verify_series -def cdl_doji(open_, high, low, close, length=None, factor=None, scalar=None, asint=True, offset=None, **kwargs): + +def cdl_doji( + open_, + high, + low, + close, + length=None, + factor=None, + scalar=None, + asint=True, + offset=None, + **kwargs, +): """Candle Type: Doji""" # Validate Arguments open_ = verify_series(open_) @@ -44,8 +56,7 @@ def cdl_doji(open_, high, low, close, length=None, factor=None, scalar=None, asi return doji -cdl_doji.__doc__ = \ -"""Candle Type: Doji +cdl_doji.__doc__ = """Candle Type: Doji A candle body is Doji, when it's shorter than 10% of the average of the 10 previous candles' high-low range. diff --git a/pandas_ta/candles/cdl_inside.py b/pandas_ta/candles/cdl_inside.py index 6855e75..a43a3c4 100644 --- a/pandas_ta/candles/cdl_inside.py +++ b/pandas_ta/candles/cdl_inside.py @@ -3,42 +3,41 @@ from pandas import DataFrame, set_option from pandas_ta.utils import candle_color, get_drift, get_offset from pandas_ta.utils import non_zero_range, real_body, verify_series + def cdl_inside(open_, high, low, close, asbool=False, offset=None, **kwargs): - """Candle Type: Inside Bar""" - # Validate arguments - open_ = verify_series(open_) - high = verify_series(high) - low = verify_series(low) - close = verify_series(close) - offset = get_offset(offset) + """Candle Type: Inside Bar""" + # Validate arguments + open_ = verify_series(open_) + high = verify_series(high) + low = verify_series(low) + close = verify_series(close) + offset = get_offset(offset) - # Calculate Result - inside = (high.diff() < 0) & (low.diff() > 0) + # Calculate Result + inside = (high.diff() < 0) & (low.diff() > 0) - if not asbool: - inside *= candle_color(open_, close) + if not asbool: + inside *= candle_color(open_, close) - # Offset - if offset != 0: - inside = inside.shift(offset) + # Offset + if offset != 0: + inside = inside.shift(offset) - # Handle fills - if "fillna" in kwargs: - inside.fillna(kwargs["fillna"], inplace=True) + # Handle fills + if "fillna" in kwargs: + inside.fillna(kwargs["fillna"], inplace=True) - if "fill_method" in kwargs: - inside.fillna(method=kwargs["fill_method"], inplace=True) + if "fill_method" in kwargs: + inside.fillna(method=kwargs["fill_method"], inplace=True) - # Name and Categorize it - inside.name = f"CDL_INSIDE" - inside.category = "candles" - - return inside + # Name and Categorize it + inside.name = f"CDL_INSIDE" + inside.category = "candles" + + return inside - -cdl_inside.__doc__ = \ -"""Candle Type: Inside Bar +cdl_inside.__doc__ = """Candle Type: Inside Bar An Inside Bar is a bar that is engulfed by the prior highs and lows of it's previous bar. In other words, the current bar is smaller than it's previous bar. diff --git a/pandas_ta/candles/ha.py b/pandas_ta/candles/ha.py index 0748622..6776d8a 100644 --- a/pandas_ta/candles/ha.py +++ b/pandas_ta/candles/ha.py @@ -19,7 +19,7 @@ def ha(open_, high, low, close, offset=None, **kwargs): "HA_open": 0.5 * (open_.iloc[0] + close.iloc[0]), "HA_high": high, "HA_low": low, - "HA_close": 0.25 * (open_ + high + low + close) + "HA_close": 0.25 * (open_ + high + low + close), }) for i in range(1, m): @@ -45,8 +45,7 @@ def ha(open_, high, low, close, offset=None, **kwargs): return df -ha.__doc__ = \ -"""Heikin Ashi Candles (HA) +ha.__doc__ = """Heikin Ashi Candles (HA) The Heikin-Ashi technique averages price data to create a Japanese candlestick chart that filters out market noise. Heikin-Ashi charts, @@ -55,7 +54,7 @@ with standard candlestick charts but differ based on the values used to create each candle. Instead of using the open, high, low, and close like standard candlestick charts, the Heikin-Ashi technique uses a modified formula based on two-period averages. This gives the chart a -smoother appearance, making it easier to spots trends and reversals, +smoother appearance, making it easier to spots trends and reversals, but also obscures gaps and some price data. Sources: diff --git a/pandas_ta/core.py b/pandas_ta/core.py index 8d3a381..c74d7e8 100644 --- a/pandas_ta/core.py +++ b/pandas_ta/core.py @@ -49,10 +49,13 @@ class Strategy: {"kind": "sma", "close": "volume", "length": 20, "prefix": "VOLUME"}, ] """ - name: str# = None # Required. - ta: List = field(default_factory=list) # Required. - description: str = None # Helpful. More descriptive version or notes or w/e. - created: str = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") # Optional. May change type later to datetime + + name: str # = None # Required. + ta: List = field(default_factory=list) # Required. + # Helpful. More descriptive version or notes or w/e. + description: str = None + # Optional. May change type later to datetime + created: str = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") def __post_init__(self): has_name = True @@ -63,7 +66,9 @@ class Strategy: ta_is_list = isinstance(self.ta, list) if self.name is None or not name_is_str: - required_args.append(" - name. Must be a string. Example: \"My TA\". Note: \"all\" is reserved.") + required_args.append( + ' - name. Must be a string. Example: "My TA". Note: "all" is reserved.' + ) has_name != has_name if self.ta is None: @@ -72,7 +77,8 @@ class Strategy: # Check that all elements of the list are dicts. # Does not check if the dicts values are valid indicator kwargs # User must check indicator documentation for all indicators args. - is_ta = all([isinstance(_, dict) and len(_.keys()) > 0 for _ in self.ta]) + is_ta = all( + [isinstance(_, dict) and len(_.keys()) > 0 for _ in self.ta]) else: s = " - ta. Format is a list of dicts. Example: [{'kind': 'sma', 'length': 10}]" s += "\n Check the indicator for the correct arguments if you receive this error." @@ -85,11 +91,13 @@ class Strategy: def total_ta(self): return len(self.ta) if self.ta is not None else 0 + # All Default Strategy AllStrategy = Strategy( name="All", - description="All the indicators with their default settings. Pandas TA default.", - ta=None + description= + "All the indicators with their default settings. Pandas TA default.", + ta=None, ) # Default (Example) Strategy. @@ -97,16 +105,32 @@ CommonStrategy = Strategy( name="Common Price and Volume SMAs", description="Common Price SMAs: 10, 20, 50, 200 and Volume SMA: 20.", ta=[ - {"kind": "sma", "length": 10}, - {"kind": "sma", "length": 20}, - {"kind": "sma", "length": 50}, - {"kind": "sma", "length": 200}, - {"kind": "sma", "close": "volume", "length": 20, "prefix": "VOL"} - ] + { + "kind": "sma", + "length": 10 + }, + { + "kind": "sma", + "length": 20 + }, + { + "kind": "sma", + "length": 50 + }, + { + "kind": "sma", + "length": 200 + }, + { + "kind": "sma", + "close": "volume", + "length": 20, + "prefix": "VOL" + }, + ], ) - # Base Class for extending a Pandas DataFrame class BasePandasObject(PandasObject): """Simple PandasObject Extension @@ -117,11 +141,24 @@ class BasePandasObject(PandasObject): Args: df (pd.DataFrame): Extends Pandas DataFrame """ + def __init__(self, df, **kwargs): - if df.empty: return + if df.empty: + return if len(df.columns) > 0: - common_names = {"Date": "date", "Time": "time", "Timestamp": "timestamp", "Datetime": "datetime", "Open": "open", "High": "high", "Low": "low", "Close": "close", "Adj Close": "adj_close", "Volume": "volume"} + common_names = { + "Date": "date", + "Time": "time", + "Timestamp": "timestamp", + "Datetime": "datetime", + "Open": "open", + "High": "high", + "Low": "low", + "Close": "close", + "Adj Close": "adj_close", + "Volume": "volume", + } # Preemptively drop the rows that are all NaNs # Might need to be moved to AnalysisIndicators.__call__() to be # toggleable via kwargs. @@ -218,42 +255,46 @@ class AnalysisIndicators(BasePandasObject): >>> apo = df.ta(kind="apo", timed=True) >>> print(apo.timed) """ + _adjusted = None _cores = cpu_count() _mp = False # DataFrame Behavioral Methods def __call__( - self, - kind: str = None, - alias: str = None, - timed: bool = False, - verbose: bool = False, - **kwargs - ): - try: - if isinstance(kind, str): - kind = kind.lower() - fn = getattr(self, kind) + self, + kind: str = None, + alias: str = None, + timed: bool = False, + verbose: bool = False, + **kwargs, + ): + try: + if isinstance(kind, str): + kind = kind.lower() + fn = getattr(self, kind) - if timed: stime = perf_counter() + if timed: + stime = perf_counter() - # Run the indicator - result = fn(**kwargs) # = getattr(self, kind)(**kwargs) + # Run the indicator + result = fn(**kwargs) # = getattr(self, kind)(**kwargs) - if timed: - result.timed = final_time(stime) - alias_str = alias + ":" if alias is not None else "" - print(f"[+] {kind}:{alias_str} {result.timed}") + if timed: + result.timed = final_time(stime) + alias_str = alias + ":" if alias is not None else "" + print(f"[+] {kind}:{alias_str} {result.timed}") - # Add an alias if passed - if alias: result.alias = f"{alias}" + # Add an alias if passed + if alias: + result.alias = f"{alias}" - return result - else: - self.help() + return result + else: + self.help() - except: pass + except BaseException: + pass # Public Get/Set DataFrame Properties @property @@ -262,7 +303,7 @@ class AnalysisIndicators(BasePandasObject): return self._adjusted @adjusted.setter - def adjusted(self, value:str) -> None: + def adjusted(self, value: str) -> None: """property: df.ta.adjusted = 'adj_close'""" if value is not None and isinstance(value, str): self._adjusted = value @@ -275,7 +316,7 @@ class AnalysisIndicators(BasePandasObject): return self._cores @cores.setter - def cores(self, value:int) -> None: + def cores(self, value: int) -> None: """property: df.ta.cores = integer""" cpus = cpu_count() if value is not None and isinstance(value, int): @@ -320,61 +361,72 @@ class AnalysisIndicators(BasePandasObject): """Returns the version.""" return version - - # Private DataFrame Methods def _add_prefix_suffix(self, result=None, **kwargs): """Add prefix and/or suffix to the result columns""" - if result is None: return + if result is None: + return else: prefix = suffix = "" delimiter = kwargs.setdefault("delimiter", "_") - if "prefix" in kwargs: prefix = f"{kwargs['prefix']}{delimiter}" - if "suffix" in kwargs: suffix = f"{delimiter}{kwargs['suffix']}" + if "prefix" in kwargs: + prefix = f"{kwargs['prefix']}{delimiter}" + if "suffix" in kwargs: + suffix = f"{delimiter}{kwargs['suffix']}" if isinstance(result, pd.Series): result.name = prefix + result.name + suffix else: - result.columns = [prefix + column + suffix for column in result.columns] - + result.columns = [ + prefix + column + suffix for column in result.columns + ] def _append(self, result=None, **kwargs): """Appends a Pandas Series or DataFrame columns to self._df.""" if "append" in kwargs and kwargs["append"]: df = self._df na_columns = self._check_na_columns() - if df is None or result is None: return + if df is None or result is None: + return elif len(na_columns): - print(f"[X] {result.name} column(s) values are all na: {', '.join(na_columns)}") + print( + f"[X] {result.name} column(s) values are all na: {', '.join(na_columns)}" + ) return else: if isinstance(result, pd.DataFrame): - # If specified in kwargs, rename the columns. If not, use the default names. - if "col_names" in kwargs and isinstance(kwargs["col_names"], tuple): - if len(kwargs["col_names"])>=len(result.columns): - for col, ind_name in zip(result.columns, kwargs["col_names"]): - df[ind_name] = result.loc[:,col] + # If specified in kwargs, rename the columns. If not, use + # the default names. + if "col_names" in kwargs and isinstance( + kwargs["col_names"], tuple): + if len(kwargs["col_names"]) >= len(result.columns): + for col, ind_name in zip(result.columns, + kwargs["col_names"]): + df[ind_name] = result.loc[:, col] else: - print(f"Not enough col_names were specified : got {len(kwargs['col_names'])}, expected {len(result.columns)}.") + print( + f"Not enough col_names were specified : got {len(kwargs['col_names'])}, expected {len(result.columns)}." + ) return else: for i, column in enumerate(result.columns): - df[column] = result.iloc[:,i] + df[column] = result.iloc[:, i] else: - ind_name = kwargs["col_names"][0] if "col_names" in kwargs and isinstance(kwargs["col_names"], tuple) else result.name + ind_name = ( + kwargs["col_names"][0] if "col_names" in kwargs and + isinstance(kwargs["col_names"], tuple) else result.name) df[ind_name] = result - def _check_na_columns(self, stdout: bool = True): """Returns the columns in which all it's values are na.""" return [x for x in self._df.columns if all(self._df[x].isna())] - def _get_column(self, series): """Attempts to get the correct series or 'column' and return it.""" df = self._df - if df is None: return + if df is None: + return # Explicitly passing a pd.Series to override default. if isinstance(series, pd.Series): @@ -388,20 +440,19 @@ class AnalysisIndicators(BasePandasObject): if series in df.columns: return df[series] else: - # Attempt to match the 'series' because it was likely misspelled. + # Attempt to match the 'series' because it was likely + # misspelled. matches = df.columns.str.match(series, case=False) match = [i for i, x in enumerate(matches) if x] # If found, awesome. Return it or return the 'series'. - cols = ', '.join(list(df.columns)) + cols = ", ".join(list(df.columns)) NOT_FOUND = f"[X] Ooops!!!: It's {series not in df.columns}, the series '{series}' was not found in {cols}" - return df.iloc[:,match[0]] if len(match) else print(NOT_FOUND) - + return df.iloc[:, match[0]] if len(match) else print(NOT_FOUND) def _indicators_by_category(self, name: str) -> list: """Returns indicators by Categorical name.""" return Category[name] if name in self.categories else None - def _mp_worker(self, arguments): """Multiprocessing Worker to handle different Methods.""" method, args, kwargs = arguments @@ -411,7 +462,6 @@ class AnalysisIndicators(BasePandasObject): else: return getattr(self, method)(*args, **kwargs)[0] - def _post_process(self, result, **kwargs) -> (pd.Series, pd.DataFrame): """Applies any additional modifications to the DataFrame * Applies prefixes and/or suffixes @@ -421,14 +471,17 @@ class AnalysisIndicators(BasePandasObject): print(f"[X] Oops! The result was not a Series or DataFrame.") return self._df else: - # Append only specific columns to the dataframe (via 'col_numbers':(0,1,3) for example) - result = result.iloc[:,[int(n) for n in kwargs['col_numbers']]] if isinstance(result, pd.DataFrame) and 'col_numbers' in kwargs and kwargs['col_numbers'] is not None else result + # Append only specific columns to the dataframe (via + # 'col_numbers':(0,1,3) for example) + result = (result.iloc[:, [int(n) for n in kwargs["col_numbers"]]] + if isinstance(result, pd.DataFrame) and + "col_numbers" in kwargs and + kwargs["col_numbers"] is not None else result) # Add prefix/suffix and append to the dataframe self._add_prefix_suffix(result=result, **kwargs) self._append(result=result, **kwargs) return result - def _strategy_mode(self, *args) -> tuple: """Helper method to determine the mode and name of the strategy. Returns tuple: (name:str, mode:dict)""" name = "All" @@ -454,7 +507,6 @@ class AnalysisIndicators(BasePandasObject): return name, mode - # Public DataFrame Methods def constants(self, append: bool, values: list): """Constants @@ -494,7 +546,6 @@ class AnalysisIndicators(BasePandasObject): for x in values: del self._df[f"{x}"] - def indicators(self, **kwargs): """List of Indicators @@ -512,10 +563,19 @@ class AnalysisIndicators(BasePandasObject): # Public non-indicator methods helper_methods = ["constants", "indicators", "strategy"] # Public df.ta.properties - ta_properties = ["adjusted", "categories", "cores", "datetime_ordered", "mp", "reverse", "version"] + ta_properties = [ + "adjusted", + "categories", + "cores", + "datetime_ordered", + "mp", + "reverse", + "version", + ] # Public non-indicator methods - ta_indicators = list((x for x in dir(pd.DataFrame().ta) if not x.startswith("_") and not x.endswith("_"))) + ta_indicators = list((x for x in dir(pd.DataFrame().ta) + if not x.startswith("_") and not x.endswith("_"))) # Add Pandas TA methods and properties to be removed removed = helper_methods + ta_properties @@ -529,7 +589,8 @@ class AnalysisIndicators(BasePandasObject): [ta_indicators.remove(x) for x in removed] # If as a list, immediately return - if as_list: return ta_indicators + if as_list: + return ta_indicators total_indicators = len(ta_indicators) header = f"Pandas TA - Technical Analysis Indicators - v{self.version}" @@ -539,7 +600,6 @@ class AnalysisIndicators(BasePandasObject): else: print(s) - def strategy(self, *args, **kwargs): """Strategy Method @@ -556,11 +616,23 @@ class AnalysisIndicators(BasePandasObject): For example, length=20 or offset=-1 or high=df["high"] ... """ cpus = cpu_count() - kwargs["append"] = True # Ensure indicators are appended to the DataFrame + # Ensure indicators are appended to the DataFrame + kwargs["append"] = True # Initialize initial_column_count = len(self._df.columns) - excluded = ["above", "above_value", "below", "below_value", "cross", "cross_value", "long_run", "short_run", "trend_return", "vp"] + excluded = [ + "above", + "above_value", + "below", + "below_value", + "cross", + "cross_value", + "long_run", + "short_run", + "trend_return", + "vp", + ] # Get the Strategy Name and mode name, mode = self._strategy_mode(*args) @@ -591,188 +663,359 @@ class AnalysisIndicators(BasePandasObject): timed = kwargs.pop("timed", False) results = [] pool = Pool(self.cores) - if timed: stime = perf_counter() + if timed: + stime = perf_counter() if mode["custom"]: - has_col_names = True if len([True for x in ta if 'col_names' in x and isinstance(x['col_names'], tuple)]) else False - custom_ta = [(ind["kind"], ind["params"] if "params" in ind and isinstance(ind["params"], tuple) else (), {**ind, **kwargs}) for ind in ta] + has_col_names = (True if len([ + True for x in ta + if "col_names" in x and isinstance(x["col_names"], tuple) + ]) else False) + custom_ta = [( + ind["kind"], + ind["params"] + if "params" in ind and isinstance(ind["params"], tuple) else (), + { + **ind, + **kwargs + }, + ) for ind in ta] if has_col_names: - if verbose: print(f"[i] No mulitproccessing support for 'col_names' option.") + if verbose: + print( + f"[i] No mulitproccessing support for 'col_names' option." + ) # Without multiprocessing: for ind in ta: - params = ind["params"] if "params" in ind and isinstance(ind["params"], tuple) else tuple() + params = (ind["params"] if "params" in ind and + isinstance(ind["params"], tuple) else tuple()) getattr(self, ind["kind"])(*params, **{**ind, **kwargs}) else: if verbose: - print(f"[i] Multiprocessing: {self.cores} of {cpu_count()} cores.") + print( + f"[i] Multiprocessing: {self.cores} of {cpu_count()} cores." + ) # Custom multiprocessing pool. Must be ordered for Chained Strategies - # May fix this to cpus if Chaining/Composition if it remains inconsistent + # May fix this to cpus if Chaining/Composition if it remains + # inconsistent results = pool.imap(self._mp_worker, custom_ta, self.cores) else: if verbose: - print(f"[i] Multiprocessing: {self.cores} of {cpu_count()} cores.") + print( + f"[i] Multiprocessing: {self.cores} of {cpu_count()} cores." + ) default_ta = [(ind, tuple(), kwargs) for ind in ta] # All and Categorical multiprocessing pool. Speed over Order. - results = pool.imap_unordered(self._mp_worker, default_ta, self.cores) + results = pool.imap_unordered(self._mp_worker, default_ta, + self.cores) pool.close() pool.join() - # Apply prefixes/suffixes and appends indicator results to the DataFrame + # Apply prefixes/suffixes and appends indicator results to the + # DataFrame [self._post_process(r, **kwargs) for r in results] - if timed: ftime = final_time(stime) + if timed: + ftime = final_time(stime) if verbose: print(f"[i] Total indicators: {len(ta)}") - print(f"[i] Columns added: {len(self._df.columns) - initial_column_count}") - if timed: print(f"[i] Runtime: {ftime}") - - + print( + f"[i] Columns added: {len(self._df.columns) - initial_column_count}" + ) + if timed: + print(f"[i] Runtime: {ftime}") # Public DataFrame Methods: Indicators and Utilities # Candles def cdl_doji(self, offset=None, **kwargs): open_ = self._get_column(kwargs.pop("open", "open")) - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = cdl_doji(open_=open_, high=high, low=low, close=close, offset=offset, **kwargs) + result = cdl_doji(open_=open_, + high=high, + low=low, + close=close, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def cdl_inside(self, offset=None, **kwargs): open_ = self._get_column(kwargs.pop("open", "open")) - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = cdl_inside(open_=open_, high=high, low=low, close=close, offset=offset, **kwargs) + result = cdl_inside(open_=open_, + high=high, + low=low, + close=close, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def ha(self, offset=None, **kwargs): open_ = self._get_column(kwargs.pop("open", "open")) - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = ha(open_=open_, high=high, low=low, close=close, offset=offset, **kwargs) + result = ha(open_=open_, + high=high, + low=low, + close=close, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) - - # Momentum def ao(self, fast=None, slow=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) - result = ao(high=high, low=low, fast=fast, slow=slow, offset=offset, **kwargs) + result = ao(high=high, + low=low, + fast=fast, + slow=slow, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def apo(self, fast=None, slow=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = apo(close=close, fast=fast, slow=slow, offset=offset, **kwargs) return self._post_process(result, **kwargs) def bias(self, length=None, mamode=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = bias(close=close, length=length, mamode=mamode, offset=offset, **kwargs) + close = self._get_column(kwargs.pop("close", "close")) + result = bias(close=close, + length=length, + mamode=mamode, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def bop(self, percentage=False, offset=None, **kwargs): - open_ = self._get_column(kwargs.pop("open", "open")) - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + open_ = self._get_column(kwargs.pop("open", "open")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("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, + percentage=percentage, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def brar(self, length=None, scalar=None, drift=None, offset=None, **kwargs): - open_ = self._get_column(kwargs.pop("open", "open")) - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + open_ = self._get_column(kwargs.pop("open", "open")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = brar(open_=open_ , high=high, low=low, close=close, length=length, scalar=scalar, drift=drift, offset=offset, **kwargs) + result = brar( + open_=open_, + high=high, + low=low, + close=close, + length=length, + scalar=scalar, + drift=drift, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def cci(self, length=None, c=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = cci(high=high, low=low, close=close, length=length, c=c, offset=offset, **kwargs) + result = cci(high=high, + low=low, + close=close, + length=length, + c=c, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def cfo(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = cfo(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def cg(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = cg(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def cmo(self, length=None, scalar=None, drift=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = cmo(close=close, length=length, scalar=scalar, drift=drift, offset=offset, **kwargs) + close = self._get_column(kwargs.pop("close", "close")) + result = cmo( + close=close, + length=length, + scalar=scalar, + drift=drift, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def coppock(self, length=None, fast=None, slow=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = coppock(close=close, length=length, fast=fast, slow=slow, offset=offset, **kwargs) + close = self._get_column(kwargs.pop("close", "close")) + result = coppock(close=close, + length=length, + fast=fast, + slow=slow, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def er(self, length=None, drift=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = er(close=close, length=length, drift=drift, offset=offset, **kwargs) + close = self._get_column(kwargs.pop("close", "close")) + result = er(close=close, + length=length, + drift=drift, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def eri(self, length=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = eri(high=high, low=low, close=close, length=length, offset=offset, **kwargs) + result = eri(high=high, + low=low, + close=close, + length=length, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def fisher(self, length=None, signal=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) - result = fisher(high=high, low=low, length=length, signal=signal, offset=offset, **kwargs) + result = fisher(high=high, + low=low, + length=length, + signal=signal, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) - def inertia(self, length=None, rvi_length=None, scalar=None, refined=None, thirds=None, mamode=None, drift=None, offset=None, **kwargs): + def inertia( + self, + length=None, + rvi_length=None, + scalar=None, + refined=None, + thirds=None, + mamode=None, + drift=None, + offset=None, + **kwargs, + ): close = self._get_column(kwargs.pop("close", "close")) if refined is not None or thirds is not None: - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) - result = inertia(close=close, high=high, low=low, length=length, rvi_length=rvi_length, scalar=scalar, refined=refined, thirds=thirds, mamode=mamode, drift=drift, offset=offset, **kwargs) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) + result = inertia( + close=close, + high=high, + low=low, + length=length, + rvi_length=rvi_length, + scalar=scalar, + refined=refined, + thirds=thirds, + mamode=mamode, + drift=drift, + offset=offset, + **kwargs, + ) else: - result = inertia(close=close, length=length, rvi_length=rvi_length, scalar=scalar, refined=refined, thirds=thirds, mamode=mamode, drift=drift, offset=offset, **kwargs) + result = inertia( + close=close, + length=length, + rvi_length=rvi_length, + scalar=scalar, + refined=refined, + thirds=thirds, + mamode=mamode, + drift=drift, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def kdj(self, length=None, signal=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = kdj(high=high, low=low, close=close, length=length, signal=signal, offset=offset, **kwargs) + result = kdj( + high=high, + low=low, + close=close, + length=length, + signal=signal, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) - def kst(self, roc1=None, roc2=None, roc3=None, roc4=None, sma1=None, sma2=None, sma3=None, sma4=None, signal=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = kst(close=close, roc1=roc1, roc2=roc2, roc3=roc3, roc4=roc4, sma1=sma1, sma2=sma2, sma3=sma3, sma4=sma4, signal=signal, offset=offset, **kwargs) + def kst( + self, + roc1=None, + roc2=None, + roc3=None, + roc4=None, + sma1=None, + sma2=None, + sma3=None, + sma4=None, + signal=None, + offset=None, + **kwargs, + ): + close = self._get_column(kwargs.pop("close", "close")) + result = kst( + close=close, + roc1=roc1, + roc2=roc2, + roc3=roc3, + roc4=roc4, + sma1=sma1, + sma2=sma2, + sma3=sma3, + sma4=sma4, + signal=signal, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def macd(self, fast=None, slow=None, signal=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = macd(close=close, fast=fast, slow=slow, signal=signal, offset=offset, **kwargs) + close = self._get_column(kwargs.pop("close", "close")) + result = macd(close=close, + fast=fast, + slow=slow, + signal=signal, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def mom(self, length=None, offset=None, **kwargs): @@ -781,48 +1024,102 @@ class AnalysisIndicators(BasePandasObject): return self._post_process(result, **kwargs) def pgo(self, length=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = pgo(high=high, low=low, close=close, length=length, offset=offset, **kwargs) + result = pgo(high=high, + low=low, + close=close, + length=length, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def ppo(self, fast=None, slow=None, scalar=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = ppo(close=close, fast=fast, slow=slow, scalar=scalar, offset=offset, **kwargs) + close = self._get_column(kwargs.pop("close", "close")) + result = ppo(close=close, + fast=fast, + slow=slow, + scalar=scalar, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) - def psl(self, open_=None, length=None, scalar=None, drift=None, offset=None, **kwargs): + def psl(self, + open_=None, + length=None, + scalar=None, + drift=None, + offset=None, + **kwargs): if open_ is not None: open_ = self._get_column(kwargs.pop("open", "open")) close = self._get_column(kwargs.pop("close", "close")) - result = psl(close=close, open_=open_, length=length, scalar=scalar, drift=drift, offset=offset, **kwargs) + result = psl( + close=close, + open_=open_, + length=length, + scalar=scalar, + drift=drift, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) - def pvo(self, fast=None, slow=None, signal=None, scalar=None, offset=None, **kwargs): + def pvo(self, + fast=None, + slow=None, + signal=None, + scalar=None, + offset=None, + **kwargs): volume = self._get_column(kwargs.pop("volume", "volume")) - result = pvo(volume=volume, fast=fast, slow=slow, signal=signal, scalar=scalar, offset=offset, **kwargs) + result = pvo( + volume=volume, + fast=fast, + slow=slow, + signal=signal, + scalar=scalar, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def roc(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = roc(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def rsi(self, length=None, scalar=None, drift=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = rsi(close=close, length=length, scalar=scalar, drift=drift, offset=offset, **kwargs) + close = self._get_column(kwargs.pop("close", "close")) + result = rsi( + close=close, + length=length, + scalar=scalar, + drift=drift, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def rvgi(self, length=None, swma_length=None, offset=None, **kwargs): - open_ = self._get_column(kwargs.pop("open", "open")) - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + open_ = self._get_column(kwargs.pop("open", "open")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = rvgi(open_=open_, high=high, low=low, close=close, length=length, swma_length=swma_length, offset=offset, **kwargs) + result = rvgi( + open_=open_, + high=high, + low=low, + close=close, + length=length, + swma_length=swma_length, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def slope(self, length=None, offset=None, **kwargs): @@ -830,118 +1127,268 @@ class AnalysisIndicators(BasePandasObject): result = slope(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) - def smi(self, fast=None, slow=None, signal=None, scalar=None, offset=None, **kwargs): + def smi(self, + fast=None, + slow=None, + signal=None, + scalar=None, + offset=None, + **kwargs): close = self._get_column(kwargs.pop("close", "close")) - result = smi(close=close, fast=fast, slow=slow, signal=signal, scalar=scalar, offset=offset, **kwargs) + result = smi( + close=close, + fast=fast, + slow=slow, + signal=signal, + scalar=scalar, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) - def squeeze(self, bb_length=None, bb_std=None, kc_length=None, kc_scalar=None, mom_length=None, mom_smooth=None, use_tr=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + def squeeze( + self, + bb_length=None, + bb_std=None, + kc_length=None, + kc_scalar=None, + mom_length=None, + mom_smooth=None, + use_tr=None, + offset=None, + **kwargs, + ): + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = squeeze(high=high, low=low, close=close, bb_length=bb_length, bb_std=bb_std, kc_length=kc_length, kc_scalar=kc_scalar, mom_length=mom_length, mom_smooth=mom_smooth, use_tr=use_tr, offset=offset, **kwargs) + result = squeeze( + high=high, + low=low, + close=close, + bb_length=bb_length, + bb_std=bb_std, + kc_length=kc_length, + kc_scalar=kc_scalar, + mom_length=mom_length, + mom_smooth=mom_smooth, + use_tr=use_tr, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) - def stoch(self, fast_k=None, slow_k=None, slow_d=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + def stoch(self, + fast_k=None, + slow_k=None, + slow_d=None, + offset=None, + **kwargs): + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = stoch(high=high, low=low, close=close, fast_k=fast_k, slow_k=slow_k, slow_d=slow_d, offset=offset, **kwargs) + result = stoch( + high=high, + low=low, + close=close, + fast_k=fast_k, + slow_k=slow_k, + slow_d=slow_d, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) - def stochrsi(self, length=None, rsi_length=None, k=None, d=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + def stochrsi(self, + length=None, + rsi_length=None, + k=None, + d=None, + offset=None, + **kwargs): + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = stochrsi(high=high, low=low, close=close, length=length, rsi_length=rsi_length, k=k, d=d, offset=offset, **kwargs) + 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 trix(self, length=None, signal=None, scalar=None, drift=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = trix(close=close, length=length, signal=signal, scalar=scalar, drift=drift, offset=offset, **kwargs) + def trix(self, + length=None, + signal=None, + scalar=None, + drift=None, + offset=None, + **kwargs): + close = self._get_column(kwargs.pop("close", "close")) + result = trix( + close=close, + length=length, + signal=signal, + scalar=scalar, + drift=drift, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def tsi(self, fast=None, slow=None, drift=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = tsi(close=close, fast=fast, slow=slow, drift=drift, offset=offset, **kwargs) + close = self._get_column(kwargs.pop("close", "close")) + result = tsi(close=close, + fast=fast, + slow=slow, + drift=drift, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) - def uo(self, fast=None, medium=None, slow=None, fast_w=None, medium_w=None, slow_w=None, drift=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + def uo( + self, + fast=None, + medium=None, + slow=None, + fast_w=None, + medium_w=None, + slow_w=None, + drift=None, + offset=None, + **kwargs, + ): + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = uo(high=high, low=low, close=close, fast=fast, medium=medium, slow=slow, fast_w=fast_w, medium_w=medium_w, slow_w=slow_w, drift=drift, offset=offset, **kwargs) + result = uo( + high=high, + low=low, + close=close, + fast=fast, + medium=medium, + slow=slow, + fast_w=fast_w, + medium_w=medium_w, + slow_w=slow_w, + drift=drift, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) - def willr(self, length=None, percentage=True, offset=None,**kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + def willr(self, length=None, percentage=True, offset=None, **kwargs): + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = willr(high=high, low=low, close=close, length=length, percentage=percentage, offset=offset, **kwargs) + result = willr( + high=high, + low=low, + close=close, + length=length, + percentage=percentage, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) - - # Overlap def dema(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = dema(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def ema(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = ema(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def fwma(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = fwma(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) - def hilo(self, high_length=None, low_length=None, mamode=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + def hilo(self, + high_length=None, + low_length=None, + mamode=None, + offset=None, + **kwargs): + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = hilo(high=high, low=low, close=close, high_length=high_length, low_length=low_length, mamode=mamode, offset=offset, **kwargs) + result = hilo( + high=high, + low=low, + close=close, + high_length=high_length, + low_length=low_length, + mamode=mamode, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def hl2(self, offset=None, **kwargs): high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + low = self._get_column(kwargs.pop("low", "low")) result = hl2(high=high, low=low, offset=offset, **kwargs) return self._post_process(result, **kwargs) def hlc3(self, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) result = hlc3(high=high, low=low, close=close, offset=offset, **kwargs) return self._post_process(result, **kwargs) def hma(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = hma(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def kama(self, length=None, fast=None, slow=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = kama(close=close, length=length, fast=fast, slow=slow, offset=offset, **kwargs) + close = self._get_column(kwargs.pop("close", "close")) + result = kama(close=close, + length=length, + fast=fast, + slow=slow, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) - def ichimoku(self, tenkan=None, kijun=None, senkou=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + def ichimoku(self, + tenkan=None, + kijun=None, + senkou=None, + offset=None, + **kwargs): + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result, span = ichimoku(high=high, low=low, close=close, tenkan=tenkan, kijun=kijun, senkou=senkou, offset=offset, **kwargs) + result, span = ichimoku( + high=high, + low=low, + close=close, + tenkan=tenkan, + kijun=kijun, + senkou=senkou, + offset=offset, + **kwargs, + ) self._add_prefix_suffix(result, **kwargs) self._add_prefix_suffix(span, **kwargs) self._append(result, **kwargs) @@ -949,28 +1396,41 @@ class AnalysisIndicators(BasePandasObject): return result, span def linreg(self, length=None, offset=None, adjust=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = linreg(close=close, length=length, offset=offset, adjust=adjust, **kwargs) + close = self._get_column(kwargs.pop("close", "close")) + result = linreg(close=close, + length=length, + offset=offset, + adjust=adjust, + **kwargs) return self._post_process(result, **kwargs) def midpoint(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = midpoint(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def midprice(self, length=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) - result = midprice(high=high, low=low, length=length, offset=offset, **kwargs) + result = midprice(high=high, + low=low, + length=length, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def ohlc4(self, offset=None, **kwargs): - open_ = self._get_column(kwargs.pop("open", "open")) - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + open_ = self._get_column(kwargs.pop("open", "open")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = ohlc4(open_=open_, high=high, low=low, close=close, offset=offset, **kwargs) + result = ohlc4(open_=open_, + high=high, + low=low, + close=close, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def pwma(self, length=None, offset=None, **kwargs): @@ -979,35 +1439,43 @@ class AnalysisIndicators(BasePandasObject): return self._post_process(result, **kwargs) def rma(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = rma(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def sinwma(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = sinwma(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def sma(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = sma(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def supertrend(self, length=None, multiplier=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = supertrend(high=high, low=low, close=close, length=length, multiplier=multiplier, offset=offset, **kwargs) + result = supertrend( + high=high, + low=low, + close=close, + length=length, + multiplier=multiplier, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def swma(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = swma(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def t3(self, length=None, a=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = t3(close=close, length=length, a=a, offset=offset, **kwargs) return self._post_process(result, **kwargs) @@ -1017,231 +1485,422 @@ class AnalysisIndicators(BasePandasObject): return self._post_process(result, **kwargs) def trima(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = trima(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def vwap(self, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) volume = self._get_column(kwargs.pop("volume", "volume")) if not self.datetime_ordered: volume.index = self._df.index - result = vwap(high=high, low=low, close=close, volume=volume, offset=offset, **kwargs) + result = vwap(high=high, + low=low, + close=close, + volume=volume, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def vwma(self, volume=None, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) volume = self._get_column(kwargs.pop("volume", "volume")) - result = vwma(close=close, volume=close, length=length, offset=offset, **kwargs) + result = vwma(close=close, + volume=close, + length=length, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def wcp(self, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) result = wcp(high=high, low=low, close=close, offset=offset, **kwargs) return self._post_process(result, **kwargs) def wma(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = wma(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def zlma(self, length=None, mamode=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = zlma(close=close, length=length, mamode=mamode, offset=offset, **kwargs) + close = self._get_column(kwargs.pop("close", "close")) + result = zlma(close=close, + length=length, + mamode=mamode, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) - - # Performance - def log_return(self, length=None, cumulative=False, percent=False, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = log_return(close=close, length=length, cumulative=cumulative, percent=percent, offset=offset, **kwargs) + def log_return(self, + length=None, + cumulative=False, + percent=False, + offset=None, + **kwargs): + close = self._get_column(kwargs.pop("close", "close")) + result = log_return( + close=close, + length=length, + cumulative=cumulative, + percent=percent, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) - def percent_return(self, length=None, cumulative=False, percent=False, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = percent_return(close=close, length=length, cumulative=cumulative, percent=percent, offset=offset, **kwargs) + def percent_return(self, + length=None, + cumulative=False, + percent=False, + offset=None, + **kwargs): + close = self._get_column(kwargs.pop("close", "close")) + result = percent_return( + close=close, + length=length, + cumulative=cumulative, + percent=percent, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) - def trend_return(self, trend=None, log=True, cumulative=None, offset=None, trend_reset=None, **kwargs): - if trend is None: return self._df + def trend_return( + self, + trend=None, + log=True, + cumulative=None, + offset=None, + trend_reset=None, + **kwargs, + ): + if trend is None: + return self._df else: close = self._get_column(kwargs.pop("close", "close")) - result = trend_return(close=close, trend=trend, log=log, cumulative=cumulative, offset=offset, trend_reset=trend_reset, **kwargs) + result = trend_return( + close=close, + trend=trend, + log=log, + cumulative=cumulative, + offset=offset, + trend_reset=trend_reset, + **kwargs, + ) return self._post_process(result, **kwargs) - - # Statistics def entropy(self, length=None, base=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = entropy(close=close, length=length, base=base, offset=offset, **kwargs) + close = self._get_column(kwargs.pop("close", "close")) + result = entropy(close=close, + length=length, + base=base, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def kurtosis(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = kurtosis(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def mad(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = mad(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def median(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = median(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def quantile(self, length=None, q=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = quantile(close=close, length=length, q=q, offset=offset, **kwargs) + close = self._get_column(kwargs.pop("close", "close")) + result = quantile(close=close, + length=length, + q=q, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def skew(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = skew(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def stdev(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = stdev(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def variance(self, length=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) result = variance(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def zscore(self, length=None, std=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = zscore(close=close, length=length, std=std, offset=offset, **kwargs) + close = self._get_column(kwargs.pop("close", "close")) + result = zscore(close=close, + length=length, + std=std, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) - - # Trend def adx(self, length=None, scalar=None, drift=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = adx(high=high, low=low, close=close, length=length, scalar=scalar, drift=drift, offset=offset, **kwargs) + result = adx( + high=high, + low=low, + close=close, + length=length, + scalar=scalar, + drift=drift, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) - def amat(self, fast=None, slow=None, mamode=None, lookback=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = amat(close=close, fast=fast, slow=slow, mamode=mamode, lookback=lookback, offset=offset, **kwargs) + def amat(self, + fast=None, + slow=None, + mamode=None, + lookback=None, + offset=None, + **kwargs): + close = self._get_column(kwargs.pop("close", "close")) + result = amat( + close=close, + fast=fast, + slow=slow, + mamode=mamode, + lookback=lookback, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def aroon(self, length=None, scalar=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) - result = aroon(high=high, low=low, length=length, scalar=scalar, offset=offset, **kwargs) + result = aroon(high=high, + low=low, + length=length, + scalar=scalar, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) - def chop(self, length=None, atr_length=None, scalar=None, drift=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + def chop( + self, + length=None, + atr_length=None, + scalar=None, + drift=None, + offset=None, + **kwargs, + ): + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = chop(high=high, low=low, close=close, length=length, atr_length=atr_length, scalar=scalar, drift=drift, offset=offset, **kwargs) + result = chop( + high=high, + low=low, + close=close, + length=length, + atr_length=atr_length, + scalar=scalar, + drift=drift, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def cksp(self, p=None, x=None, q=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = cksp(high=high, low=low, close=close, p=p, x=x, q=q, offset=offset, **kwargs) + result = cksp(high=high, + low=low, + close=close, + p=p, + x=x, + q=q, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def decay(self, length=None, mode=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = decay(close=close, length=length, mode=mode, offset=offset, **kwargs) + close = self._get_column(kwargs.pop("close", "close")) + result = decay(close=close, + length=length, + mode=mode, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def decreasing(self, length=None, asint=True, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = decreasing(close=close, length=length, asint=asint, offset=offset, **kwargs) + close = self._get_column(kwargs.pop("close", "close")) + result = decreasing(close=close, + length=length, + asint=asint, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def dpo(self, length=None, centered=True, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = dpo(close=close, length=length, centered=centered, offset=offset, **kwargs) + close = self._get_column(kwargs.pop("close", "close")) + result = dpo(close=close, + length=length, + centered=centered, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def increasing(self, length=None, asint=True, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = increasing(close=close, length=length, asint=asint, offset=offset, **kwargs) + close = self._get_column(kwargs.pop("close", "close")) + result = increasing(close=close, + length=length, + asint=asint, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) - def long_run(self, fast=None, slow=None, length=None, offset=None, **kwargs): - if fast is None and slow is None: return self._df + def long_run(self, + fast=None, + slow=None, + length=None, + offset=None, + **kwargs): + if fast is None and slow is None: + return self._df else: - result = long_run(fast=fast, slow=slow, length=length, offset=offset, **kwargs) + result = long_run(fast=fast, + slow=slow, + length=length, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def psar(self, af=None, max_af=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", None)) - result = psar(high=high, low=low, close=close, af=af, max_af=max_af, offset=offset, **kwargs) + result = psar( + high=high, + low=low, + close=close, + af=af, + max_af=max_af, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def qstick(self, length=None, offset=None, **kwargs): - open_ = self._get_column(kwargs.pop("open", "open")) + open_ = self._get_column(kwargs.pop("open", "open")) close = self._get_column(kwargs.pop("close", "close")) - result = qstick(open_=open_, close=close, length=length, offset=offset, **kwargs) + result = qstick(open_=open_, + close=close, + length=length, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) - def short_run(self, fast=None, slow=None, length=None, offset=None, **kwargs): - if fast is None and slow is None: return self._df + def short_run(self, + fast=None, + slow=None, + length=None, + offset=None, + **kwargs): + if fast is None and slow is None: + return self._df else: - result = short_run(fast=fast, slow=slow, length=length, offset=offset, **kwargs) + result = short_run(fast=fast, + slow=slow, + length=length, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) - def supertrend(self, period=None, multiplier=None, mamode=None, drift=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + def supertrend( + self, + period=None, + multiplier=None, + mamode=None, + drift=None, + offset=None, + **kwargs, + ): + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = supertrend(high=high, low=low, close=close, period=period, multiplier=multiplier, mamode=mamode, drift=drift, offset=offset, **kwargs) + result = supertrend( + high=high, + low=low, + close=close, + period=period, + multiplier=multiplier, + mamode=mamode, + drift=drift, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def ttm_trend(self, length=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = ttm_trend(high=high, low=low, close=close, length=length, offset=offset, **kwargs) + result = ttm_trend(high=high, + low=low, + close=close, + length=length, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def vortex(self, drift=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = vortex(high=high, low=low, close=close, drift=drift, offset=offset, **kwargs) + result = vortex(high=high, + low=low, + close=close, + drift=drift, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) - - # Utility def above(self, asint=True, offset=None, **kwargs): a = self._get_column(kwargs.pop("close", "a")) b = self._get_column(kwargs.pop("close", "b")) - result = above(series_a=a, series_b=b, asint=asint, offset=offset, **kwargs) + result = above(series_a=a, + series_b=b, + asint=asint, + offset=offset, + **kwargs) # self._add_prefix_suffix(result, **kwargs) # self._append(result, **kwargs) @@ -1249,7 +1908,11 @@ class AnalysisIndicators(BasePandasObject): def above_value(self, value=None, asint=True, offset=None, **kwargs): a = self._get_column(kwargs.pop("close", "a")) - result = above_value(series_a=a, value=value, asint=asint, offset=offset, **kwargs) + result = above_value(series_a=a, + value=value, + asint=asint, + offset=offset, + **kwargs) # self._add_prefix_suffix(result, **kwargs) # self._append(result, **kwargs) @@ -1258,14 +1921,22 @@ class AnalysisIndicators(BasePandasObject): def below(self, asint=True, offset=None, **kwargs): a = self._get_column(kwargs.pop("close", "a")) b = self._get_column(kwargs.pop("close", "b")) - result = below(series_a=a, series_b=b, asint=asint, offset=offset, **kwargs) + result = below(series_a=a, + series_b=b, + asint=asint, + offset=offset, + **kwargs) # self._add_prefix_suffix(result, **kwargs) # self._append(result, **kwargs) return self._post_process(result, **kwargs) def below_value(self, value=None, asint=True, offset=None, **kwargs): a = self._get_column(kwargs.pop("close", "a")) - result = below_value(series_a=a, value=value, asint=asint, offset=offset, **kwargs) + result = below_value(series_a=a, + value=value, + asint=asint, + offset=offset, + **kwargs) # self._add_prefix_suffix(result, **kwargs) # self._append(result, **kwargs) @@ -1274,217 +1945,454 @@ class AnalysisIndicators(BasePandasObject): def cross(self, above=True, asint=True, offset=None, **kwargs): a = self._get_column(kwargs.pop("close", "a")) b = self._get_column(kwargs.pop("close", "b")) - result = cross(series_a=a, series_b=b, above=above, asint=asint, offset=offset, **kwargs) + result = cross(series_a=a, + series_b=b, + above=above, + asint=asint, + offset=offset, + **kwargs) # self._add_prefix_suffix(result, **kwargs) # self._append(result, **kwargs) return self._post_process(result, **kwargs) - def cross_value(self, value=None, above=True, asint=True, offset=None, **kwargs): + def cross_value(self, + value=None, + above=True, + asint=True, + offset=None, + **kwargs): a = self._get_column(a, f"{a}") - result = cross_value(series_a=a, value=value, above=above, asint=asint, offset=offset, **kwargs) + result = cross_value(series_a=a, + value=value, + above=above, + asint=asint, + offset=offset, + **kwargs) # self._add_prefix_suffix(result, **kwargs) # self._append(result, **kwargs) return self._post_process(result, **kwargs) - - # Volatility def aberration(self, length=None, atr_length=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = aberration(high=high, low=low, close=close, length=length, atr_length=atr_length, offset=offset, **kwargs) + result = aberration( + high=high, + low=low, + close=close, + length=length, + atr_length=atr_length, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def accbands(self, length=None, c=None, mamode=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = accbands(high=high, low=low, close=close, length=length, c=c, mamode=mamode, offset=offset, **kwargs) + result = accbands( + high=high, + low=low, + close=close, + length=length, + c=c, + mamode=mamode, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def atr(self, length=None, mamode=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = atr(high=high, low=low, close=close, length=length, mamode=mamode, offset=offset, **kwargs) + result = atr( + high=high, + low=low, + close=close, + length=length, + mamode=mamode, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) - def bbands(self, length=None, stdev=None, mamode=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = bbands(close=close, length=length, stdev=stdev, mamode=mamode, offset=offset, **kwargs) + def bbands(self, + length=None, + stdev=None, + mamode=None, + offset=None, + **kwargs): + close = self._get_column(kwargs.pop("close", "close")) + result = bbands( + close=close, + length=length, + stdev=stdev, + mamode=mamode, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) - def donchian(self, lower_length=None, upper_length=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + def donchian(self, + lower_length=None, + upper_length=None, + offset=None, + **kwargs): + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) - result = donchian(high=high, low=low, lower_length=lower_length, upper_length=upper_length, offset=offset, **kwargs) + result = donchian( + high=high, + low=low, + lower_length=lower_length, + upper_length=upper_length, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def kc(self, length=None, scalar=None, mamode=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = kc(high=high, low=low, close=close, length=length, scalar=scalar, mamode=mamode, offset=offset, **kwargs) + result = kc( + high=high, + low=low, + close=close, + length=length, + scalar=scalar, + mamode=mamode, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def massi(self, fast=None, slow=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) - result = massi(high=high, low=low, fast=fast, slow=slow, offset=offset, **kwargs) + result = massi(high=high, + low=low, + fast=fast, + slow=slow, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) - def natr(self, length=None, mamode=None, scalar=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + def natr(self, + length=None, + mamode=None, + scalar=None, + offset=None, + **kwargs): + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = natr(high=high, low=low, close=close, length=length, mamode=mamode, scalar=scalar, offset=offset, **kwargs) + result = natr( + high=high, + low=low, + close=close, + length=length, + mamode=mamode, + scalar=scalar, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def pdist(self, drift=None, offset=None, **kwargs): - open_ = self._get_column(kwargs.pop("open", "open")) - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + open_ = self._get_column(kwargs.pop("open", "open")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = pdist(open_=open_, high=high, low=low, close=close, drift=drift, offset=offset, **kwargs) + result = pdist( + open_=open_, + high=high, + low=low, + close=close, + drift=drift, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) - def rvi(self, length=None, scalar=None, refined=None, thirds=None, mamode=None, drift=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + def rvi( + self, + length=None, + scalar=None, + refined=None, + thirds=None, + mamode=None, + drift=None, + offset=None, + **kwargs, + ): + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = rvi(high=high, low=low, close=close, length=length, scalar=scalar, refined=refined, thirds=thirds, mamode=mamode, drift=drift, offset=offset, **kwargs) + result = rvi( + high=high, + low=low, + close=close, + length=length, + scalar=scalar, + refined=refined, + thirds=thirds, + mamode=mamode, + drift=drift, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def true_range(self, drift=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = true_range(high=high, low=low, close=close, drift=drift, offset=offset, **kwargs) + result = true_range(high=high, + low=low, + close=close, + drift=drift, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) def ui(self, length=None, scalar=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) - result = ui(close=close, length=length, scalar=scalar, offset=offset, **kwargs) + close = self._get_column(kwargs.pop("close", "close")) + result = ui(close=close, + length=length, + scalar=scalar, + offset=offset, + **kwargs) return self._post_process(result, **kwargs) - - # Volume def ad(self, open_=None, signed=True, offset=None, **kwargs): if open_ is not None: open_ = self._get_column(kwargs.pop("open", "open")) - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) - close = self._get_column(kwargs.pop("close", "close")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) + close = self._get_column(kwargs.pop("close", "close")) volume = self._get_column(kwargs.pop("volume", "volume")) - result = ad(high=high, low=low, close=close, volume=volume, open_=open_, signed=signed, offset=offset, **kwargs) + result = ad( + high=high, + low=low, + close=close, + volume=volume, + open_=open_, + signed=signed, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) - def adosc(self, open_=None, fast=None, slow=None, signed=True, offset=None, **kwargs): + def adosc(self, + open_=None, + fast=None, + slow=None, + signed=True, + offset=None, + **kwargs): if open_ is not None: open_ = self._get_column(kwargs.pop("open", "open")) - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) - close = self._get_column(kwargs.pop("close", "close")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) + close = self._get_column(kwargs.pop("close", "close")) volume = self._get_column(kwargs.pop("volume", "volume")) - result = adosc(high=high, low=low, close=close, volume=volume, open_=open_, fast=fast, slow=slow, signed=signed, offset=offset, **kwargs) + result = adosc( + high=high, + low=low, + close=close, + volume=volume, + open_=open_, + fast=fast, + slow=slow, + signed=signed, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) - def aobv(self, fast=None, slow=None, mamode=None, max_lookback=None, min_lookback=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + def aobv( + self, + fast=None, + slow=None, + mamode=None, + max_lookback=None, + min_lookback=None, + offset=None, + **kwargs, + ): + close = self._get_column(kwargs.pop("close", "close")) volume = self._get_column(kwargs.pop("volume", "volume")) - result = aobv(close=close, volume=volume, fast=fast, slow=slow, mamode=mamode, max_lookback=max_lookback, min_lookback=min_lookback, offset=offset, **kwargs) + result = aobv( + close=close, + volume=volume, + fast=fast, + slow=slow, + mamode=mamode, + max_lookback=max_lookback, + min_lookback=min_lookback, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def cmf(self, open_=None, length=None, offset=None, **kwargs): if open_ is not None: open_ = self._get_column(kwargs.pop("open", "open")) - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) volume = self._get_column(kwargs.pop("volume", "volume")) - result = cmf(high=high, low=low, close=close, volume=volume, open_=open_, length=length, offset=offset, **kwargs) + result = cmf( + high=high, + low=low, + close=close, + volume=volume, + open_=open_, + length=length, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def efi(self, length=None, mamode=None, offset=None, drift=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) volume = self._get_column(kwargs.pop("volume", "volume")) - result = efi(close=close, volume=volume, length=length, offset=offset, mamode=mamode, drift=drift, **kwargs) + result = efi( + close=close, + volume=volume, + length=length, + offset=offset, + mamode=mamode, + drift=drift, + **kwargs, + ) return self._post_process(result, **kwargs) def eom(self, length=None, divisor=None, offset=None, drift=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) - close = self._get_column(kwargs.pop("close", "close")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) + close = self._get_column(kwargs.pop("close", "close")) volume = self._get_column(kwargs.pop("volume", "volume")) - result = eom(high=high, low=low, close=close, volume=volume, length=length, divisor=divisor, offset=offset, drift=drift, **kwargs) + result = eom( + high=high, + low=low, + close=close, + volume=volume, + length=length, + divisor=divisor, + offset=offset, + drift=drift, + **kwargs, + ) return self._post_process(result, **kwargs) def mfi(self, length=None, drift=None, offset=None, **kwargs): - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) - close = self._get_column(kwargs.pop("close", "close")) + high = self._get_column(kwargs.pop("high", "high")) + low = self._get_column(kwargs.pop("low", "low")) + close = self._get_column(kwargs.pop("close", "close")) volume = self._get_column(kwargs.pop("volume", "volume")) - result = mfi(high=high, low=low, close=close, volume=volume, length=length, drift=drift, offset=offset, **kwargs) + result = mfi( + high=high, + low=low, + close=close, + volume=volume, + length=length, + drift=drift, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) - def nvi(self, length=None, initial=None, signed=True, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + def nvi(self, + length=None, + initial=None, + signed=True, + offset=None, + **kwargs): + close = self._get_column(kwargs.pop("close", "close")) volume = self._get_column(kwargs.pop("volume", "volume")) - result = nvi(close=close, volume=volume, length=length, initial=initial, signed=signed, offset=offset, **kwargs) + result = nvi( + close=close, + volume=volume, + length=length, + initial=initial, + signed=signed, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def obv(self, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) volume = self._get_column(kwargs.pop("volume", "volume")) result = obv(close=close, volume=volume, offset=offset, **kwargs) return self._post_process(result, **kwargs) - def pvi(self, length=None, initial=None, signed=True, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + def pvi(self, + length=None, + initial=None, + signed=True, + offset=None, + **kwargs): + close = self._get_column(kwargs.pop("close", "close")) volume = self._get_column(kwargs.pop("volume", "volume")) - result = pvi(close=close, volume=volume, length=length, initial=initial, signed=signed, offset=offset, **kwargs) + result = pvi( + close=close, + volume=volume, + length=length, + initial=initial, + signed=signed, + offset=offset, + **kwargs, + ) return self._post_process(result, **kwargs) def pvol(self, volume=None, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) volume = self._get_column(kwargs.pop("volume", "volume")) result = pvol(close=close, volume=volume, offset=offset, **kwargs) return self._post_process(result, **kwargs) def pvt(self, offset=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) volume = self._get_column(kwargs.pop("volume", "volume")) result = pvt(close=close, volume=volume, offset=offset, **kwargs) return self._post_process(result, **kwargs) def vp(self, width=None, percent=None, **kwargs): - close = self._get_column(kwargs.pop("close", "close")) + close = self._get_column(kwargs.pop("close", "close")) volume = self._get_column(kwargs.pop("volume", "volume")) - result = vp(close=close, volume=volume, width=width, percent=percent, **kwargs) + result = vp(close=close, + volume=volume, + width=width, + percent=percent, + **kwargs) return self._post_process(result, **kwargs) diff --git a/pandas_ta/momentum/ao.py b/pandas_ta/momentum/ao.py index 8442360..83df8e6 100644 --- a/pandas_ta/momentum/ao.py +++ b/pandas_ta/momentum/ao.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, verify_series + def ao(high, low, fast=None, slow=None, offset=None, **kwargs): """Indicator: Awesome Oscillator (AO)""" # Validate Arguments @@ -10,7 +11,8 @@ def ao(high, low, fast=None, slow=None, offset=None, **kwargs): slow = int(slow) if slow and slow > 0 else 34 if slow < fast: fast, slow = slow, fast - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else fast + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else fast) offset = get_offset(offset) # Calculate Result @@ -24,21 +26,19 @@ def ao(high, low, fast=None, slow=None, offset=None, **kwargs): ao = ao.shift(offset) # Handle fills - if 'fillna' in kwargs: - ao.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - ao.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + ao.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + ao.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it ao.name = f"AO_{fast}_{slow}" - ao.category = 'momentum' + ao.category = "momentum" return ao - -ao.__doc__ = \ -"""Awesome Oscillator (AO) +ao.__doc__ = """Awesome Oscillator (AO) The Awesome Oscillator is an indicator used to measure a security's momentum. AO is generally used to affirm trends or to anticipate possible reversals. @@ -67,4 +67,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/apo.py b/pandas_ta/momentum/apo.py index a0d1a5c..84b6bc4 100644 --- a/pandas_ta/momentum/apo.py +++ b/pandas_ta/momentum/apo.py @@ -2,6 +2,7 @@ from pandas_ta.overlap import sma from pandas_ta.utils import get_offset, verify_series + def apo(close, fast=None, slow=None, offset=None, **kwargs): """Indicator: Absolute Price Oscillator (APO)""" # Validate Arguments @@ -10,7 +11,8 @@ def apo(close, fast=None, slow=None, offset=None, **kwargs): slow = int(slow) if slow and slow > 0 else 26 if slow < fast: fast, slow = slow, fast - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else fast + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else fast) offset = get_offset(offset) # Calculate Result @@ -23,21 +25,19 @@ def apo(close, fast=None, slow=None, offset=None, **kwargs): apo = apo.shift(offset) # Handle fills - if 'fillna' in kwargs: - apo.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - apo.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + apo.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + apo.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it apo.name = f"APO_{fast}_{slow}" - apo.category = 'momentum' + apo.category = "momentum" return apo - -apo.__doc__ = \ -"""Absolute Price Oscillator (APO) +apo.__doc__ = """Absolute Price Oscillator (APO) The Absolute Price Oscillator is an indicator used to measure a security's momentum. It is simply the difference of two Exponential Moving Averages diff --git a/pandas_ta/momentum/bias.py b/pandas_ta/momentum/bias.py index d0b247f..2825b8d 100644 --- a/pandas_ta/momentum/bias.py +++ b/pandas_ta/momentum/bias.py @@ -6,6 +6,7 @@ from ..overlap.rma import rma from ..overlap.wma import wma from ..utils import get_offset, verify_series, zero + def bias(close, length=None, mamode=None, offset=None, **kwargs): """Indicator: Bias (BIAS)""" # Validate Arguments @@ -15,15 +16,15 @@ def bias(close, length=None, mamode=None, offset=None, **kwargs): offset = get_offset(offset) # Calculate Result - if mamode is None or mamode == 'sma': + if mamode is None or mamode == "sma": ma = sma(close, length=length, **kwargs) - if mamode == 'ema': + if mamode == "ema": ma = ema(close, length=length, **kwargs) - if mamode == 'hma': + if mamode == "hma": ma = hma(close, length=length, **kwargs) - if mamode == 'rma': + if mamode == "rma": ma = rma(close, length=length, **kwargs) - if mamode == 'wma': + if mamode == "wma": ma = wma(close, length=length, **kwargs) bias = (close / ma) - 1 @@ -33,21 +34,19 @@ def bias(close, length=None, mamode=None, offset=None, **kwargs): bias = bias.shift(offset) # Handle fills - if 'fillna' in kwargs: - bias.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - bias.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + bias.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + bias.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it bias.name = f"BIAS_{ma.name}" - bias.category = 'momentum' + bias.category = "momentum" return bias - -bias.__doc__ = \ -"""Bias (BIAS) +bias.__doc__ = """Bias (BIAS) Rate of change between the source and a moving average. @@ -58,7 +57,7 @@ Sources: Calculation: Default Inputs: length=26, MA='sma' - + BIAS = (close - MA(close, length)) / MA(close, length) = (close / MA(close, length)) - 1 @@ -75,4 +74,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/bop.py b/pandas_ta/momentum/bop.py index 93f90c3..960f6aa 100644 --- a/pandas_ta/momentum/bop.py +++ b/pandas_ta/momentum/bop.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, non_zero_range, verify_series + def bop(open_, high, low, close, scalar=None, offset=None, **kwargs): """Indicator: Balance of Power (BOP)""" # Validate Arguments @@ -33,9 +34,7 @@ def bop(open_, high, low, close, scalar=None, offset=None, **kwargs): return bop - -bop.__doc__ = \ -"""Balance of Power (BOP) +bop.__doc__ = """Balance of Power (BOP) Balance of Power measure the market strength of buyers against sellers. @@ -59,4 +58,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/brar.py b/pandas_ta/momentum/brar.py index e66ad13..0937bed 100644 --- a/pandas_ta/momentum/brar.py +++ b/pandas_ta/momentum/brar.py @@ -2,7 +2,16 @@ from pandas import DataFrame from ..utils import get_drift, get_offset, non_zero_range, verify_series -def brar(open_, high, low, close, length=None, scalar=None, drift=None, offset=None, **kwargs): + +def brar(open_, + high, + low, + close, + length=None, + scalar=None, + drift=None, + offset=None, + **kwargs): """Indicator: BRAR (BRAR)""" # Validate Arguments open_ = verify_series(open_) @@ -20,8 +29,8 @@ def brar(open_, high, low, close, length=None, scalar=None, drift=None, offset=N hcy = non_zero_range(high, close.shift(drift)) cyl = non_zero_range(close.shift(drift), low) - hcy[hcy < 0] = 0 # Zero negative values - cyl[cyl < 0] = 0 # "" + hcy[hcy < 0] = 0 # Zero negative values + cyl[cyl < 0] = 0 # "" ar = scalar * high_open_range.rolling(length).sum() ar /= open_low_range.rolling(length).sum() @@ -35,30 +44,28 @@ def brar(open_, high, low, close, length=None, scalar=None, drift=None, offset=N br = ar.shift(offset) # Handle fills - if 'fillna' in kwargs: - ar.fillna(kwargs['fillna'], inplace=True) - br.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - ar.fillna(method=kwargs['fill_method'], inplace=True) - br.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + ar.fillna(kwargs["fillna"], inplace=True) + br.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + ar.fillna(method=kwargs["fill_method"], inplace=True) + br.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it _props = f"_{length}" ar.name = f"AR{_props}" br.name = f"BR{_props}" - ar.category = br.category = 'momentum' + ar.category = br.category = "momentum" # Prepare DataFrame to return brardf = DataFrame({ar.name: ar, br.name: br}) brardf.name = f"BRAR{_props}" - brardf.category = 'momentum' + brardf.category = "momentum" return brardf - -brar.__doc__ = \ -"""BRAR (BRAR) +brar.__doc__ = """BRAR (BRAR) BR and AR @@ -96,4 +103,4 @@ Kwargs: Returns: pd.DataFrame: ar, br columns. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/cci.py b/pandas_ta/momentum/cci.py index 1244032..8114b38 100644 --- a/pandas_ta/momentum/cci.py +++ b/pandas_ta/momentum/cci.py @@ -4,6 +4,7 @@ from ..overlap.sma import sma from ..statistics.mad import mad from ..utils import get_offset, verify_series + def cci(high, low, close, length=None, c=None, offset=None, **kwargs): """Indicator: Commodity Channel Index (CCI)""" # Validate Arguments @@ -27,21 +28,19 @@ def cci(high, low, close, length=None, c=None, offset=None, **kwargs): cci = cci.shift(offset) # Handle fills - if 'fillna' in kwargs: - cci.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - cci.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + cci.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + cci.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it cci.name = f"CCI_{length}_{c}" - cci.category = 'momentum' + cci.category = "momentum" return cci - -cci.__doc__ = \ -"""Commodity Channel Index (CCI) +cci.__doc__ = """Commodity Channel Index (CCI) Commodity Channel Index is a momentum oscillator used to primarily identify overbought and oversold levels relative to a mean. @@ -73,4 +72,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/cfo.py b/pandas_ta/momentum/cfo.py index 8a379f3..be28887 100644 --- a/pandas_ta/momentum/cfo.py +++ b/pandas_ta/momentum/cfo.py @@ -2,6 +2,7 @@ from pandas_ta.overlap import linreg from pandas_ta.utils import get_drift, get_offset, verify_series + def cfo(close, length=None, scalar=None, drift=None, offset=None, **kwargs): """Indicator: Chande Forcast Oscillator (CFO)""" # Validate Arguments @@ -11,8 +12,8 @@ def cfo(close, length=None, scalar=None, drift=None, offset=None, **kwargs): drift = get_drift(drift) offset = get_offset(offset) - #Finding linear regression of Series - cfo = scalar * (close - linreg(close, length=length, tsf=True)) + # Finding linear regression of Series + cfo = scalar * (close - linreg(close, length=length, tsf=True)) cfo /= close # Offset @@ -31,8 +32,8 @@ def cfo(close, length=None, scalar=None, drift=None, offset=None, **kwargs): return cfo -cfo.__doc__ = \ -"""Chande Forcast Oscillator (CFO) + +cfo.__doc__ = """Chande Forcast Oscillator (CFO) The Forecast Oscillator calculates the percentage difference between the actual price and the Time Series Forecast (the endpoint of a linear regression line). diff --git a/pandas_ta/momentum/cg.py b/pandas_ta/momentum/cg.py index 77f351a..7259feb 100644 --- a/pandas_ta/momentum/cg.py +++ b/pandas_ta/momentum/cg.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, verify_series, weights + def cg(close, length=None, offset=None, **kwargs): """Indicator: Center of Gravity (CG)""" # Validate Arguments @@ -18,21 +19,19 @@ def cg(close, length=None, offset=None, **kwargs): cg = cg.shift(offset) # Handle fills - if 'fillna' in kwargs: - cg.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - cg.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + cg.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + cg.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it cg.name = f"CG_{length}" - cg.category = 'momentum' + cg.category = "momentum" return cg - -cg.__doc__ = \ -"""Center of Gravity (CG) +cg.__doc__ = """Center of Gravity (CG) The Center of Gravity Indicator by John Ehlers attempts to identify turning points while exhibiting zero lag and smoothing. diff --git a/pandas_ta/momentum/cmo.py b/pandas_ta/momentum/cmo.py index bcfc01d..f4947a4 100644 --- a/pandas_ta/momentum/cmo.py +++ b/pandas_ta/momentum/cmo.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from ..utils import get_drift, get_offset, verify_series + def cmo(close, length=None, scalar=None, drift=None, offset=None, **kwargs): """Indicator: Chande Momentum Oscillator (CMO)""" # Validate Arguments @@ -45,9 +46,7 @@ def cmo(close, length=None, scalar=None, drift=None, offset=None, **kwargs): return cmo - -cmo.__doc__ = \ -"""Chande Momentum Oscillator (CMO) +cmo.__doc__ = """Chande Momentum Oscillator (CMO) Attempts to capture the momentum of an asset with overbought at 50 and oversold at -50. @@ -75,4 +74,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/coppock.py b/pandas_ta/momentum/coppock.py index e7bfa34..18eb8e0 100644 --- a/pandas_ta/momentum/coppock.py +++ b/pandas_ta/momentum/coppock.py @@ -4,6 +4,7 @@ from ..overlap.rma import rma from ..overlap.wma import wma from ..utils import get_offset, verify_series + def coppock(close, length=None, fast=None, slow=None, offset=None, **kwargs): """Indicator: Coppock Curve (COPC)""" # Validate Arguments @@ -11,7 +12,8 @@ def coppock(close, length=None, fast=None, slow=None, offset=None, **kwargs): length = int(length) if length and length > 0 else 10 fast = int(fast) if fast and fast > 0 else 11 slow = int(slow) if slow and slow > 0 else 14 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) offset = get_offset(offset) # Calculate Result @@ -23,21 +25,19 @@ def coppock(close, length=None, fast=None, slow=None, offset=None, **kwargs): coppock = coppock.shift(offset) # Handle fills - if 'fillna' in kwargs: - coppock.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - coppock.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + coppock.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + coppock.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it coppock.name = f"COPC_{fast}_{slow}_{length}" - coppock.category = 'momentum' + coppock.category = "momentum" return coppock - -coppock.__doc__ = \ -"""Coppock Curve (COPC) +coppock.__doc__ = """Coppock Curve (COPC) Coppock Curve (originally called the "Trendex Model") is a momentum indicator is designed for use on a monthly time scale. Although designed for monthly @@ -71,4 +71,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/er.py b/pandas_ta/momentum/er.py index 8b027a6..71e8169 100644 --- a/pandas_ta/momentum/er.py +++ b/pandas_ta/momentum/er.py @@ -3,6 +3,7 @@ from pandas import DataFrame, concat from pandas_ta.overlap import rma from pandas_ta.utils import get_drift, get_offset, verify_series, signals + def er(close, length=None, drift=None, offset=None, **kwargs): """Indicator: Efficiency Ratio (ER)""" # Validate arguments @@ -23,35 +24,33 @@ def er(close, length=None, drift=None, offset=None, **kwargs): er = er.shift(offset) # Handle fills - if 'fillna' in kwargs: - er.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - er.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + er.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + er.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it er.name = f"ER_{length}" er.category = "momentum" - signal_indicators = kwargs.pop('signal_indicators', False) + signal_indicators = kwargs.pop("signal_indicators", False) if signal_indicators: signalsdf = concat( [ - DataFrame( - {er.name: er} - ), + DataFrame({er.name: er}), signals( indicator=er, - xa=kwargs.pop('xa', 80), - xb=kwargs.pop('xb', 20), - xserie=kwargs.pop('xserie', None), - xserie_a=kwargs.pop('xserie_a', None), - xserie_b=kwargs.pop('xserie_b', None), - cross_values=kwargs.pop('cross_values', False), - cross_series=kwargs.pop('cross_series', True), + xa=kwargs.pop("xa", 80), + xb=kwargs.pop("xb", 20), + xserie=kwargs.pop("xserie", None), + xserie_a=kwargs.pop("xserie_a", None), + xserie_b=kwargs.pop("xserie_b", None), + cross_values=kwargs.pop("cross_values", False), + cross_series=kwargs.pop("cross_series", True), offset=offset, ), ], - axis=1 + axis=1, ) return signalsdf @@ -59,9 +58,7 @@ def er(close, length=None, drift=None, offset=None, **kwargs): return er - -er.__doc__ = \ -"""Efficiency Ratio (ER) +er.__doc__ = """Efficiency Ratio (ER) The Efficiency Ratio was invented by Perry J. Kaufman and presented in his book "New Trading Systems and Methods". It is designed to account for market noise or volatility. @@ -91,4 +88,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/eri.py b/pandas_ta/momentum/eri.py index 1ad9c43..73b8d2f 100644 --- a/pandas_ta/momentum/eri.py +++ b/pandas_ta/momentum/eri.py @@ -3,6 +3,7 @@ from pandas import DataFrame from pandas_ta.overlap import ema from pandas_ta.utils import get_offset, verify_series + def eri(high, low, close, length=None, offset=None, **kwargs): """Indicator: Elder Ray Index (ERI)""" # Validate arguments @@ -23,12 +24,12 @@ def eri(high, low, close, length=None, offset=None, **kwargs): bear = bear.shift(offset) # Handle fills - if 'fillna' in kwargs: - bull.fillna(kwargs['fillna'], inplace=True) - bear.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - bull.fillna(method=kwargs['fill_method'], inplace=True) - bear.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + bull.fillna(kwargs["fillna"], inplace=True) + bear.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + bull.fillna(method=kwargs["fill_method"], inplace=True) + bear.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it bull.name = f"BULLP_{length}" @@ -44,9 +45,7 @@ def eri(high, low, close, length=None, offset=None, **kwargs): return df - -eri.__doc__ = \ -"""Elder Ray Index (ERI) +eri.__doc__ = """Elder Ray Index (ERI) Elder's Bulls Ray Index contains his Bull and Bear Powers. Which are useful ways to look at the price and see the strength behind the market. Bull Power @@ -56,7 +55,7 @@ consensus of value. Bears Power measures the capability of sellers, to drag prices below an average consensus of value. Using them in tandem with a measure of trend allows you to identify favourable entry points. We hope you've found this to be a useful -discussion of the Bulls and Bears Power indicators. +discussion of the Bulls and Bears Power indicators. Sources: https://admiralmarkets.com/education/articles/forex-indicators/bears-and-bulls-power-indicator @@ -82,4 +81,4 @@ Kwargs: Returns: pd.DataFrame: bull power and bear power columns. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/fisher.py b/pandas_ta/momentum/fisher.py index 1d6c66b..8e0874a 100644 --- a/pandas_ta/momentum/fisher.py +++ b/pandas_ta/momentum/fisher.py @@ -5,6 +5,7 @@ from pandas import DataFrame, Series from pandas_ta.overlap import ema, hl2 from pandas_ta.utils import get_offset, high_low_range, verify_series, zero + def fisher(high, low, length=None, signal=None, offset=None, **kwargs): """Indicator: Fisher Transform (FISHT)""" # Validate Arguments @@ -29,8 +30,10 @@ def fisher(high, low, length=None, signal=None, offset=None, **kwargs): result = [npNaN for _ in range(0, length - 1)] + [0] for i in range(length, m): v = 0.66 * position[i] + 0.67 * v - if v < -0.99: v = -0.999 - if v > 0.99: v = 0.999 + if v < -0.99: + v = -0.999 + if v > 0.99: + v = 0.999 result.append(0.5 * (nplog((1 + v) / (1 - v)) + result[i - 1])) fisher = Series(result, index=high.index) signalma = fisher.shift(signal) @@ -63,9 +66,7 @@ def fisher(high, low, length=None, signal=None, offset=None, **kwargs): return df - -fisher.__doc__ = \ -"""Fisher Transform (FISHT) +fisher.__doc__ = """Fisher Transform (FISHT) Attempts to identify significant price reversals by normalizing prices over a user-specified number of periods. A reversal signal is suggested when the the @@ -110,4 +111,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/inertia.py b/pandas_ta/momentum/inertia.py index 71d1a30..64ac7dc 100644 --- a/pandas_ta/momentum/inertia.py +++ b/pandas_ta/momentum/inertia.py @@ -3,7 +3,21 @@ from pandas_ta.overlap import linreg from pandas_ta.volatility import rvi from pandas_ta.utils import get_drift, get_offset, non_zero_range, verify_series -def inertia(close=None, high=None, low=None, length=None, rvi_length=None, scalar=None, refined=None, thirds=None, mamode=None, drift=None, offset=None, **kwargs): + +def inertia( + close=None, + high=None, + low=None, + length=None, + rvi_length=None, + scalar=None, + refined=None, + thirds=None, + mamode=None, + drift=None, + offset=None, + **kwargs, +): """Indicator: Inertia (INERTIA)""" # Validate Arguments close = verify_series(close) @@ -22,10 +36,26 @@ def inertia(close=None, high=None, low=None, length=None, rvi_length=None, scala # Calculate Result _mode = "" if refined: - rvi_ = rvi(close, high=high, low=low, length=rvi_length, scalar=scalar, refined=refined, mamode=mamode) + rvi_ = rvi( + close, + high=high, + low=low, + length=rvi_length, + scalar=scalar, + refined=refined, + mamode=mamode, + ) _mode = "r" elif thirds: - rvi_ = rvi(close, high=high, low=low, length=rvi_length, scalar=scalar, thirds=thirds, mamode=mamode) + rvi_ = rvi( + close, + high=high, + low=low, + length=rvi_length, + scalar=scalar, + thirds=thirds, + mamode=mamode, + ) _mode = "t" else: rvi_ = rvi(close, length=rvi_length, scalar=scalar, mamode=mamode) @@ -37,10 +67,10 @@ def inertia(close=None, high=None, low=None, length=None, rvi_length=None, scala inertia = inertia.shift(offset) # Handle fills - if 'fillna' in kwargs: - inertia.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - inertia.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + inertia.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + inertia.fillna(method=kwargs["fill_method"], inplace=True) # Name & Category _props = f"_{length}_{rvi_length}" @@ -50,9 +80,7 @@ def inertia(close=None, high=None, low=None, length=None, rvi_length=None, scala return inertia - -inertia.__doc__ = \ -"""Inertia (INERTIA) +inertia.__doc__ = """Inertia (INERTIA) Inertia was developed by Donald Dorsey and was introduced his article in September, 1995. It is the Relative Vigor Index smoothed by the Least @@ -85,4 +113,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/kdj.py b/pandas_ta/momentum/kdj.py index 7f947ad..be717b7 100644 --- a/pandas_ta/momentum/kdj.py +++ b/pandas_ta/momentum/kdj.py @@ -3,7 +3,14 @@ from pandas import DataFrame from ..overlap.rma import rma from ..utils import get_offset, non_zero_range, verify_series -def kdj(high=None, low=None, close=None, length=None, signal=None, offset=None, **kwargs): + +def kdj(high=None, + low=None, + close=None, + length=None, + signal=None, + offset=None, + **kwargs): """Indicator: KDJ (KDJ)""" # Validate Arguments high = verify_series(high) @@ -17,7 +24,8 @@ def kdj(high=None, low=None, close=None, length=None, signal=None, offset=None, highest_high = high.rolling(length).max() lowest_low = low.rolling(length).min() - fastk = 100 * (close - lowest_low) / non_zero_range(highest_high, lowest_low) + fastk = 100 * (close - lowest_low) / non_zero_range(highest_high, + lowest_low) k = rma(fastk, length=signal) d = rma(k, length=signal) @@ -30,33 +38,31 @@ def kdj(high=None, low=None, close=None, length=None, signal=None, offset=None, j = j.shift(offset) # Handle fills - if 'fillna' in kwargs: - k.fillna(kwargs['fillna'], inplace=True) - d.fillna(kwargs['fillna'], inplace=True) - j.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - k.fillna(method=kwargs['fill_method'], inplace=True) - d.fillna(method=kwargs['fill_method'], inplace=True) - j.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + k.fillna(kwargs["fillna"], inplace=True) + d.fillna(kwargs["fillna"], inplace=True) + j.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + k.fillna(method=kwargs["fill_method"], inplace=True) + d.fillna(method=kwargs["fill_method"], inplace=True) + j.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it _params = f"_{length}_{signal}" k.name = f"K{_params}" d.name = f"D{_params}" j.name = f"J{_params}" - k.category = d.category = j.category = 'momentum' + k.category = d.category = j.category = "momentum" # Prepare DataFrame to return kdjdf = DataFrame({k.name: k, d.name: d, j.name: j}) kdjdf.name = f"KDJ{_params}" - kdjdf.category = 'momentum' + kdjdf.category = "momentum" return kdjdf - -kdj.__doc__ = \ -"""KDJ (KDJ) +kdj.__doc__ = """KDJ (KDJ) The KDJ indicator is actually a derived form of the Slow Stochastic with the only difference being an extra line @@ -94,4 +100,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/kst.py b/pandas_ta/momentum/kst.py index 211a501..01df8e4 100644 --- a/pandas_ta/momentum/kst.py +++ b/pandas_ta/momentum/kst.py @@ -3,7 +3,22 @@ from pandas import DataFrame from .roc import roc from ..utils import get_drift, get_offset, verify_series -def kst(close, roc1=None, roc2=None, roc3=None, roc4=None, sma1=None, sma2=None, sma3=None, sma4=None, signal=None, drift=None, offset=None, **kwargs): + +def kst( + close, + roc1=None, + roc2=None, + roc3=None, + roc4=None, + sma1=None, + sma2=None, + sma3=None, + sma4=None, + signal=None, + drift=None, + offset=None, + **kwargs, +): """Indicator: 'Know Sure Thing' (KST)""" # Validate arguments close = verify_series(close) @@ -36,12 +51,12 @@ def kst(close, roc1=None, roc2=None, roc3=None, roc4=None, sma1=None, sma2=None, kst_signal = kst_signal.shift(offset) # Handle fills - if 'fillna' in kwargs: - kst.fillna(kwargs['fillna'], inplace=True) - kst_signal.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - kst.fillna(method=kwargs['fill_method'], inplace=True) - kst_signal.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + kst.fillna(kwargs["fillna"], inplace=True) + kst_signal.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + kst.fillna(method=kwargs["fill_method"], inplace=True) + kst_signal.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it kst.name = f"KST_{roc1}_{roc2}_{roc3}_{roc4}_{sma1}_{sma2}_{sma3}_{sma4}" @@ -57,9 +72,7 @@ def kst(close, roc1=None, roc2=None, roc3=None, roc4=None, sma1=None, sma2=None, return kstdf - -kst.__doc__ = \ -"""'Know Sure Thing' (KST) +kst.__doc__ = """'Know Sure Thing' (KST) The 'Know Sure Thing' is a momentum based oscillator and based on ROC. @@ -101,4 +114,4 @@ Kwargs: Returns: pd.DataFrame: kst and kst_signal columns -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/macd.py b/pandas_ta/momentum/macd.py index 8fe7aa1..39366ad 100644 --- a/pandas_ta/momentum/macd.py +++ b/pandas_ta/momentum/macd.py @@ -3,6 +3,7 @@ from pandas import DataFrame, concat from ..overlap.ema import ema from ..utils import get_offset, verify_series, signals + def macd(close, fast=None, slow=None, signal=None, offset=None, **kwargs): """Indicator: Moving Average, Convergence/Divergence (MACD)""" # Validate arguments @@ -79,7 +80,7 @@ def macd(close, fast=None, slow=None, signal=None, offset=None, **kwargs): offset=offset, ), ], - axis=1 + axis=1, ) return signalsdf @@ -87,9 +88,7 @@ def macd(close, fast=None, slow=None, signal=None, offset=None, **kwargs): return df - -macd.__doc__ = \ -"""Moving Average Convergence Divergence (MACD) +macd.__doc__ = """Moving Average Convergence Divergence (MACD) The MACD is a popular indicator to that is used to identify a security's trend. While APO and MACD are the same calculation, MACD also returns two more series @@ -120,4 +119,4 @@ Kwargs: Returns: pd.DataFrame: macd, histogram, signal columns. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/mom.py b/pandas_ta/momentum/mom.py index 6dffc01..90bc50d 100644 --- a/pandas_ta/momentum/mom.py +++ b/pandas_ta/momentum/mom.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, verify_series + def mom(close, length=None, offset=None, **kwargs): """Indicator: Momentum (MOM)""" # Validate Arguments @@ -16,21 +17,19 @@ def mom(close, length=None, offset=None, **kwargs): mom = mom.shift(offset) # Handle fills - if 'fillna' in kwargs: - mom.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - mom.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + mom.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + mom.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it mom.name = f"MOM_{length}" - mom.category = 'momentum' + mom.category = "momentum" return mom - -mom.__doc__ = \ -"""Momentum (MOM) +mom.__doc__ = """Momentum (MOM) Momentum is an indicator used to measure a security's speed (or strength) of movement. Or simply the change in price. @@ -54,4 +53,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/pgo.py b/pandas_ta/momentum/pgo.py index 8699f6f..c15a56d 100644 --- a/pandas_ta/momentum/pgo.py +++ b/pandas_ta/momentum/pgo.py @@ -3,6 +3,7 @@ from pandas_ta.overlap import ema, sma from pandas_ta.volatility import atr from pandas_ta.utils import get_offset, verify_series + def pgo(high, low, close, length=None, offset=None, **kwargs): """Indicator: Pretty Good Oscillator (PGO)""" # Validate arguments @@ -21,10 +22,10 @@ def pgo(high, low, close, length=None, offset=None, **kwargs): pgo = pgo.shift(offset) # Handle fills - if 'fillna' in kwargs: - pgo.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - pgo.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + pgo.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + pgo.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it pgo.name = f"PGO_{length}" @@ -33,9 +34,7 @@ def pgo(high, low, close, length=None, offset=None, **kwargs): return pgo - -pgo.__doc__ = \ -"""Pretty Good Oscillator (PGO) +pgo.__doc__ = """Pretty Good Oscillator (PGO) The Pretty Good Oscillator indicator was created by Mark Johnson to measure the distance of the current close from its N-day Simple Moving Average, expressed in terms of an average true range over a similar period. Johnson's approach was to use it as a breakout system for longer term trades. Long if greater than 3.0 and @@ -66,4 +65,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/ppo.py b/pandas_ta/momentum/ppo.py index bdcceac..c566a2d 100644 --- a/pandas_ta/momentum/ppo.py +++ b/pandas_ta/momentum/ppo.py @@ -3,7 +3,14 @@ from pandas import DataFrame from pandas_ta.overlap import ema, sma from pandas_ta.utils import get_offset, verify_series -def ppo(close, fast=None, slow=None, signal=None, scalar=None, offset=None, **kwargs): + +def ppo(close, + fast=None, + slow=None, + signal=None, + scalar=None, + offset=None, + **kwargs): """Indicator: Percentage Price Oscillator (PPO)""" # Validate Arguments close = verify_series(close) @@ -13,7 +20,8 @@ def ppo(close, fast=None, slow=None, signal=None, scalar=None, offset=None, **kw scalar = float(scalar) if scalar else 100 if slow < fast: fast, slow = slow, fast - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else fast + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else fast) offset = get_offset(offset) # Calculate Result @@ -32,14 +40,14 @@ def ppo(close, fast=None, slow=None, signal=None, scalar=None, offset=None, **kw signalma = signalma.shift(offset) # Handle fills - if 'fillna' in kwargs: - ppo.fillna(kwargs['fillna'], inplace=True) - histogram.fillna(kwargs['fillna'], inplace=True) - signalma.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - ppo.fillna(method=kwargs['fill_method'], inplace=True) - histogram.fillna(method=kwargs['fill_method'], inplace=True) - signalma.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + ppo.fillna(kwargs["fillna"], inplace=True) + histogram.fillna(kwargs["fillna"], inplace=True) + signalma.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + ppo.fillna(method=kwargs["fill_method"], inplace=True) + histogram.fillna(method=kwargs["fill_method"], inplace=True) + signalma.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it _props = f"_{fast}_{slow}_{signal}" @@ -57,9 +65,7 @@ def ppo(close, fast=None, slow=None, signal=None, scalar=None, offset=None, **kw return df - -ppo.__doc__ = \ -"""Percentage Price Oscillator (PPO) +ppo.__doc__ = """Percentage Price Oscillator (PPO) The Percentage Price Oscillator is similar to MACD in measuring momentum. @@ -91,4 +97,4 @@ Kwargs: Returns: pd.DataFrame: ppo, histogram, signal columns -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/psl.py b/pandas_ta/momentum/psl.py index f06218f..d27cfe6 100644 --- a/pandas_ta/momentum/psl.py +++ b/pandas_ta/momentum/psl.py @@ -2,7 +2,14 @@ from numpy import sign as npSign from ..utils import get_drift, get_offset, verify_series -def psl(close, open_=None, length=None, scalar=None, drift=None, offset=None, **kwargs): + +def psl(close, + open_=None, + length=None, + scalar=None, + drift=None, + offset=None, + **kwargs): """Indicator: Psychological Line (PSL)""" # Validate Arguments close = verify_series(close) @@ -19,7 +26,7 @@ def psl(close, open_=None, length=None, scalar=None, drift=None, offset=None, ** diff = npSign(close.diff(drift)) diff.fillna(0, inplace=True) - diff[diff <= 0] = 0 # Zero negative values + diff[diff <= 0] = 0 # Zero negative values psl = scalar * diff.rolling(length).sum() psl /= length @@ -29,22 +36,20 @@ def psl(close, open_=None, length=None, scalar=None, drift=None, offset=None, ** psl = psl.shift(offset) # Handle fills - if 'fillna' in kwargs: - psl.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - psl.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + psl.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + psl.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it _props = f"_{length}" psl.name = f"PSL{_props}" - psl.category = 'momentum' + psl.category = "momentum" return psl - -psl.__doc__ = \ -"""Psychological Line (PSL) +psl.__doc__ = """Psychological Line (PSL) The Psychological Line is an oscillator-type indicator that compares the number of the rising periods to the total number of periods. In other @@ -82,4 +87,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/pvo.py b/pandas_ta/momentum/pvo.py index a08f7c0..f67ca9a 100644 --- a/pandas_ta/momentum/pvo.py +++ b/pandas_ta/momentum/pvo.py @@ -3,7 +3,14 @@ from pandas import DataFrame from pandas_ta.overlap import ema from pandas_ta.utils import get_offset, verify_series -def pvo(volume, fast=None, slow=None, signal=None, scalar=None, offset=None, **kwargs): + +def pvo(volume, + fast=None, + slow=None, + signal=None, + scalar=None, + offset=None, + **kwargs): """Indicator: Percentage Volume Oscillator (PVO)""" # Validate Arguments volume = verify_series(volume) @@ -31,14 +38,14 @@ def pvo(volume, fast=None, slow=None, signal=None, scalar=None, offset=None, **k signalma = signalma.shift(offset) # Handle fills - if 'fillna' in kwargs: - pvo.fillna(kwargs['fillna'], inplace=True) - histogram.fillna(kwargs['fillna'], inplace=True) - signalma.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - pvo.fillna(method=kwargs['fill_method'], inplace=True) - histogram.fillna(method=kwargs['fill_method'], inplace=True) - signalma.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + pvo.fillna(kwargs["fillna"], inplace=True) + histogram.fillna(kwargs["fillna"], inplace=True) + signalma.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + pvo.fillna(method=kwargs["fill_method"], inplace=True) + histogram.fillna(method=kwargs["fill_method"], inplace=True) + signalma.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it _props = f"_{fast}_{slow}_{signal}" @@ -56,9 +63,7 @@ def pvo(volume, fast=None, slow=None, signal=None, scalar=None, offset=None, **k return df - -pvo.__doc__ = \ -"""Percentage Volume Oscillator (PVO) +pvo.__doc__ = """Percentage Volume Oscillator (PVO) Percentage Volume Oscillator is a Momentum Oscillator for Volume. diff --git a/pandas_ta/momentum/roc.py b/pandas_ta/momentum/roc.py index 5676b49..54fc150 100644 --- a/pandas_ta/momentum/roc.py +++ b/pandas_ta/momentum/roc.py @@ -2,12 +2,14 @@ from .mom import mom from ..utils import get_offset, verify_series + def roc(close, length=None, offset=None, **kwargs): """Indicator: Rate of Change (ROC)""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 10 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) offset = get_offset(offset) # Calculate Result @@ -18,21 +20,19 @@ def roc(close, length=None, offset=None, **kwargs): roc = roc.shift(offset) # Handle fills - if 'fillna' in kwargs: - roc.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - roc.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + roc.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + roc.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it roc.name = f"ROC_{length}" - roc.category = 'momentum' + roc.category = "momentum" return roc - -roc.__doc__ = \ -"""Rate of Change (ROC) +roc.__doc__ = """Rate of Change (ROC) Rate of Change is an indicator is also referred to as Momentum (yeah, confusingly). It is a pure momentum oscillator that measures the percent change in price with the @@ -58,4 +58,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/rsi.py b/pandas_ta/momentum/rsi.py index abcf502..426ad17 100644 --- a/pandas_ta/momentum/rsi.py +++ b/pandas_ta/momentum/rsi.py @@ -3,6 +3,7 @@ from pandas import DataFrame, concat from pandas_ta.overlap import rma from pandas_ta.utils import get_drift, get_offset, verify_series, signals + def rsi(close, length=None, scalar=None, drift=None, offset=None, **kwargs): """Indicator: Relative Strength Index (RSI)""" # Validate arguments @@ -55,7 +56,7 @@ def rsi(close, length=None, scalar=None, drift=None, offset=None, **kwargs): offset=offset, ), ], - axis=1 + axis=1, ) return signalsdf @@ -63,9 +64,7 @@ def rsi(close, length=None, scalar=None, drift=None, offset=None, **kwargs): return rsi - -rsi.__doc__ = \ -"""Relative Strength Index (RSI) +rsi.__doc__ = """Relative Strength Index (RSI) The Relative Strength Index is popular momentum oscillator used to measure the velocity as well as the magnitude of directional price movements. @@ -100,4 +99,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/rvgi.py b/pandas_ta/momentum/rvgi.py index c35c738..a588543 100644 --- a/pandas_ta/momentum/rvgi.py +++ b/pandas_ta/momentum/rvgi.py @@ -3,7 +3,15 @@ from pandas import DataFrame from pandas_ta.overlap import swma from pandas_ta.utils import get_offset, non_zero_range, verify_series -def rvgi(open_, high, low, close, length=None, swma_length=None, offset=None, **kwargs): + +def rvgi(open_, + high, + low, + close, + length=None, + swma_length=None, + offset=None, + **kwargs): """Indicator: Relative Vigor Index (RVGI)""" # Validate Arguments open_ = verify_series(open_) @@ -19,7 +27,7 @@ def rvgi(open_, high, low, close, length=None, swma_length=None, offset=None, ** # Calculate Result numerator = swma(close_open_range, length=swma_length).rolling(length).sum() denominator = swma(high_low_range, length=swma_length).rolling(length).sum() - + rvgi = numerator / denominator signal = swma(rvgi, length=swma_length) @@ -29,12 +37,12 @@ def rvgi(open_, high, low, close, length=None, swma_length=None, offset=None, ** signal = signal.shift(offset) # Handle fills - if 'fillna' in kwargs: - rvgi.fillna(kwargs['fillna'], inplace=True) - signal.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - rvgi.fillna(method=kwargs['fill_method'], inplace=True) - signal.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + rvgi.fillna(kwargs["fillna"], inplace=True) + signal.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + rvgi.fillna(method=kwargs["fill_method"], inplace=True) + signal.fillna(method=kwargs["fill_method"], inplace=True) # Name & Category rvgi.name = f"RVGI_{length}_{swma_length}" @@ -49,12 +57,10 @@ def rvgi(open_, high, low, close, length=None, swma_length=None, offset=None, ** return df - -rvgi.__doc__ = \ -"""Relative Vigor Index (RVGI) +rvgi.__doc__ = """Relative Vigor Index (RVGI) The Relative Vigor Index attempts to measure the strength of a trend relative to -its closing price to its trading range. It is based on the belief that it tends +its closing price to its trading range. It is based on the belief that it tends to close higher than they open in uptrends or close lower than they open in downtrends. @@ -84,4 +90,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/slope.py b/pandas_ta/momentum/slope.py index 0206378..afc8755 100644 --- a/pandas_ta/momentum/slope.py +++ b/pandas_ta/momentum/slope.py @@ -2,7 +2,16 @@ from math import atan, pi from pandas_ta.utils import get_offset, verify_series -def slope(close, length=None, as_angle=None, to_degrees=None, vertical=None, offset=None, **kwargs): + +def slope( + close, + length=None, + as_angle=None, + to_degrees=None, + vertical=None, + offset=None, + **kwargs, +): """Indicator: Slope""" # Validate arguments close = verify_series(close) @@ -29,15 +38,14 @@ def slope(close, length=None, as_angle=None, to_degrees=None, vertical=None, off slope.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it - slope.name = f"SLOPE_{length}" if not as_angle else f"ANGLE{'d' if to_degrees else 'r'}_{length}" + slope.name = (f"SLOPE_{length}" if not as_angle else + f"ANGLE{'d' if to_degrees else 'r'}_{length}") slope.category = "momentum" return slope - -slope.__doc__ = \ -"""Slope +slope.__doc__ = """Slope Returns the slope of a series of length n. Can convert the slope to angle. Default: slope. @@ -66,4 +74,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/smi.py b/pandas_ta/momentum/smi.py index 8ba7ace..fd4ea19 100644 --- a/pandas_ta/momentum/smi.py +++ b/pandas_ta/momentum/smi.py @@ -4,7 +4,14 @@ from .tsi import tsi from pandas_ta.overlap import ema from pandas_ta.utils import get_offset, verify_series, signals -def smi(close, fast=None, slow=None, signal=None, scalar=None, offset=None, **kwargs): + +def smi(close, + fast=None, + slow=None, + signal=None, + scalar=None, + offset=None, + **kwargs): """Indicator: SMI Ergodic Indicator (SMIIO)""" # Validate arguments close = verify_series(close) @@ -54,9 +61,7 @@ def smi(close, fast=None, slow=None, signal=None, scalar=None, offset=None, **kw return df - -smi.__doc__ = \ -"""SMI Ergodic Indicator (SMI) +smi.__doc__ = """SMI Ergodic Indicator (SMI) The SMI Ergodic Indicator is the same as the True Strength Index (TSI) developed by William Blau, except the SMI includes a signal line. The SMI uses double @@ -95,4 +100,4 @@ Kwargs: Returns: pd.DataFrame: smi, signal, oscillator columns. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/squeeze.py b/pandas_ta/momentum/squeeze.py index 50a3888..80ff723 100644 --- a/pandas_ta/momentum/squeeze.py +++ b/pandas_ta/momentum/squeeze.py @@ -10,7 +10,21 @@ from pandas_ta.volatility import bbands, kc, true_range from pandas_ta.utils import get_drift, get_offset, high_low_range from pandas_ta.utils import unsigned_differences, verify_series -def squeeze(high, low, close, bb_length=None, bb_std=None, kc_length=None, kc_scalar=None, mom_length=None, mom_smooth=None, use_tr=None, offset=None, **kwargs): + +def squeeze( + high, + low, + close, + bb_length=None, + bb_std=None, + kc_length=None, + kc_scalar=None, + mom_length=None, + mom_smooth=None, + use_tr=None, + offset=None, + **kwargs, +): """Indicator: Squeeze Momentum (SQZ)""" # Validate arguments high = verify_series(high) @@ -19,7 +33,7 @@ def squeeze(high, low, close, bb_length=None, bb_std=None, kc_length=None, kc_sc offset = get_offset(offset) bb_length = int(bb_length) if bb_length and bb_length > 0 else 20 - bb_std = float(bb_std) if bb_std and bb_std > 0 else 2. + bb_std = float(bb_std) if bb_std and bb_std > 0 else 2.0 kc_length = int(kc_length) if kc_length and kc_length > 0 else 20 kc_scalar = float(kc_scalar) if kc_scalar and kc_scalar > 0 else 1.5 mom_length = int(mom_length) if mom_length and mom_length > 0 else 12 @@ -33,11 +47,17 @@ def squeeze(high, low, close, bb_length=None, bb_std=None, kc_length=None, kc_sc def simplify_columns(df, n=3): df.columns = df.columns.str.lower() - return [c.split('_')[0][n-1:n] for c in df.columns] + return [c.split("_")[0][n - 1:n] for c in df.columns] # Calculate Result bbd = bbands(close, length=bb_length, std=bb_std, mamode=mamode) - kch = kc(high, low, close, length=kc_length, scalar=kc_scalar, mamode=mamode, tr=use_tr) + kch = kc(high, + low, + close, + length=kc_length, + scalar=kc_scalar, + mamode=mamode, + tr=use_tr) # Simplify KC and BBAND column names for dynamic access bbd.columns = simplify_columns(bbd) @@ -45,8 +65,8 @@ def squeeze(high, low, close, bb_length=None, bb_std=None, kc_length=None, kc_sc if lazybear: highest_high = high.rolling(kc_length).max() - lowest_low = low.rolling(kc_length).min() - avg_ = 0.25 * (highest_high + lowest_low) + 0.5 * kch.b + lowest_low = low.rolling(kc_length).min() + avg_ = 0.25 * (highest_high + lowest_low) + 0.5 * kch.b squeeze = linreg(close - avg_, length=kc_length) @@ -91,7 +111,7 @@ def squeeze(high, low, close, bb_length=None, bb_std=None, kc_length=None, kc_sc squeeze.name: squeeze, f"SQZ_ON": squeeze_on.astype(int) if asint else squeeze_on, f"SQZ_OFF": squeeze_off.astype(int) if asint else squeeze_off, - f"SQZ_NO": no_squeeze.astype(int) if asint else no_squeeze + f"SQZ_NO": no_squeeze.astype(int) if asint else no_squeeze, } df = DataFrame(data) df.name = squeeze.name @@ -146,8 +166,7 @@ def squeeze(high, low, close, bb_length=None, bb_std=None, kc_length=None, kc_sc return df -squeeze.__doc__ = \ -"""Squeeze (SQZ) +squeeze.__doc__ = """Squeeze (SQZ) The default is based on John Carter's "TTM Squeeze" indicator, as discussed in his book "Mastering the Trade" (chapter 11). The Squeeze indicator attempts @@ -209,7 +228,7 @@ Kwargs: tr (value, optional): Use True Range for Keltner Channels. Default: True asint (value, optional): Use integers instead of bool. Default: True mamode (value, optional): Which MA to use. Default: "sma" - lazybear (value, optional): Use LazyBear's TradingView implementation. + lazybear (value, optional): Use LazyBear's TradingView implementation. Default: False detailed (value, optional): Return additional variations of SQZ for visualization. Default: False @@ -219,4 +238,4 @@ Kwargs: Returns: pd.DataFrame: SQZ, SQZ_ON, SQZ_OFF, NO_SQZ columns by default. More detailed columns if 'detailed' kwarg is True. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/stoch.py b/pandas_ta/momentum/stoch.py index 807896e..40f2f90 100644 --- a/pandas_ta/momentum/stoch.py +++ b/pandas_ta/momentum/stoch.py @@ -3,7 +3,15 @@ from pandas import DataFrame from pandas_ta.overlap import sma from pandas_ta.utils import get_offset, non_zero_range, verify_series -def stoch(high, low, close, k=None, d=None, smooth_k=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) @@ -15,10 +23,10 @@ def stoch(high, low, close, k=None, d=None, smooth_k=None, offset=None, **kwargs offset = get_offset(offset) # Calculate Result - lowest_low = low.rolling(k).min() + lowest_low = low.rolling(k).min() highest_high = high.rolling(k).max() - stoch = 100 * (close - lowest_low) + stoch = 100 * (close - lowest_low) stoch /= non_zero_range(highest_high, lowest_low) stoch_k = sma(stoch, length=smooth_k) @@ -53,9 +61,7 @@ def stoch(high, low, close, k=None, d=None, smooth_k=None, offset=None, **kwargs return df - -stoch.__doc__ = \ -"""Stochastic (STOCH) +stoch.__doc__ = """Stochastic (STOCH) 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 @@ -96,4 +102,4 @@ Kwargs: Returns: pd.DataFrame: %K, %D columns. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/stochrsi.py b/pandas_ta/momentum/stochrsi.py index 48f685f..2f5da6a 100644 --- a/pandas_ta/momentum/stochrsi.py +++ b/pandas_ta/momentum/stochrsi.py @@ -4,7 +4,14 @@ 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): + +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) @@ -16,10 +23,10 @@ def stochrsi(close, length=None, rsi_length=None, k=None, d=None, offset=None, * # Calculate Result rsi_ = rsi(close, length=rsi_length) - lowest_rsi = rsi_.rolling(length).min() + lowest_rsi = rsi_.rolling(length).min() highest_rsi = rsi_.rolling(length).max() - stoch = 100 * (rsi_ - lowest_rsi) + stoch = 100 * (rsi_ - lowest_rsi) stoch /= non_zero_range(highest_rsi, lowest_rsi) stochrsi_k = sma(stoch, length=k) @@ -54,9 +61,7 @@ def stochrsi(close, length=None, rsi_length=None, k=None, d=None, offset=None, * return df - -stochrsi.__doc__ = \ -"""Stochastic (STOCHRSI) +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) @@ -99,4 +104,4 @@ Kwargs: Returns: pd.DataFrame: RSI %K, RSI %D columns. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/trix.py b/pandas_ta/momentum/trix.py index 74c195c..660f3c1 100644 --- a/pandas_ta/momentum/trix.py +++ b/pandas_ta/momentum/trix.py @@ -3,14 +3,22 @@ from pandas import DataFrame from pandas_ta.overlap.ema import ema from pandas_ta.utils import get_drift, get_offset, verify_series -def trix(close, length=None, signal=None, scalar=None, drift=None, offset=None, **kwargs): + +def trix(close, + length=None, + signal=None, + scalar=None, + drift=None, + offset=None, + **kwargs): """Indicator: Trix (TRIX)""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 30 signal = int(signal) if signal and signal > 0 else 9 scalar = float(scalar) if scalar else 100 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) drift = get_drift(drift) offset = get_offset(offset) @@ -28,12 +36,12 @@ def trix(close, length=None, signal=None, scalar=None, drift=None, offset=None, trix_signal = trix_signal.shift(offset) # Handle fills - if 'fillna' in kwargs: - trix.fillna(kwargs['fillna'], inplace=True) - trix_signal.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - trix.fillna(method=kwargs['fill_method'], inplace=True) - trix_signal.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + trix.fillna(kwargs["fillna"], inplace=True) + trix_signal.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + trix.fillna(method=kwargs["fill_method"], inplace=True) + trix_signal.fillna(method=kwargs["fill_method"], inplace=True) # Name & Category trix.name = f"TRIX_{length}_{signal}" @@ -48,9 +56,7 @@ def trix(close, length=None, signal=None, scalar=None, drift=None, offset=None, return df - -trix.__doc__ = \ -"""Trix (TRIX) +trix.__doc__ = """Trix (TRIX) TRIX is a momentum oscillator to identify divergences. @@ -81,4 +87,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/tsi.py b/pandas_ta/momentum/tsi.py index fa95bb0..864b6fc 100644 --- a/pandas_ta/momentum/tsi.py +++ b/pandas_ta/momentum/tsi.py @@ -2,7 +2,14 @@ from pandas_ta.overlap import ema from pandas_ta.utils import get_drift, get_offset, verify_series -def tsi(close, fast=None, slow=None, scalar=None, drift=None, offset=None, **kwargs): + +def tsi(close, + fast=None, + slow=None, + scalar=None, + drift=None, + offset=None, + **kwargs): """Indicator: True Strength Index (TSI)""" # Validate Arguments close = verify_series(close) @@ -42,9 +49,7 @@ def tsi(close, fast=None, slow=None, scalar=None, drift=None, offset=None, **kwa return tsi - -tsi.__doc__ = \ -"""True Strength Index (TSI) +tsi.__doc__ = """True Strength Index (TSI) The True Strength Index is a momentum indicator used to identify short-term swings while in the direction of the trend as well as determining overbought @@ -81,4 +86,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/uo.py b/pandas_ta/momentum/uo.py index b6b90d6..3c87952 100644 --- a/pandas_ta/momentum/uo.py +++ b/pandas_ta/momentum/uo.py @@ -2,7 +2,21 @@ from pandas import DataFrame from ..utils import get_drift, get_offset, verify_series -def uo(high, low, close, fast=None, medium=None, slow=None, fast_w=None, medium_w=None, slow_w=None, drift=None, offset=None, **kwargs): + +def uo( + high, + low, + close, + fast=None, + medium=None, + slow=None, + fast_w=None, + medium_w=None, + slow_w=None, + drift=None, + offset=None, + **kwargs, +): """Indicator: Ultimate Oscillator (UO)""" # Validate arguments high = verify_series(high) @@ -21,9 +35,13 @@ def uo(high, low, close, fast=None, medium=None, slow=None, fast_w=None, medium_ slow_w = float(slow_w) if slow_w and slow_w > 0 else 1.0 # Calculate Result - tdf = DataFrame({'high': high, 'low': low, f"close_{drift}": close.shift(drift)}) - max_h_or_pc = tdf.loc[:, ['high', f"close_{drift}"]].max(axis=1) - min_l_or_pc = tdf.loc[:, ['low', f"close_{drift}"]].min(axis=1) + tdf = DataFrame({ + "high": high, + "low": low, + f"close_{drift}": close.shift(drift) + }) + max_h_or_pc = tdf.loc[:, ["high", f"close_{drift}"]].max(axis=1) + min_l_or_pc = tdf.loc[:, ["low", f"close_{drift}"]].min(axis=1) del tdf bp = close - min_l_or_pc @@ -33,8 +51,9 @@ def uo(high, low, close, fast=None, medium=None, slow=None, fast_w=None, medium_ medium_avg = bp.rolling(medium).sum() / tr.rolling(medium).sum() slow_avg = bp.rolling(slow).sum() / tr.rolling(slow).sum() - total_weight = fast_w + medium_w + slow_w - weights = (fast_w * fast_avg) + (medium_w * medium_avg) + (slow_w * slow_avg) + total_weight = fast_w + medium_w + slow_w + weights = (fast_w * fast_avg) + (medium_w * medium_avg) + (slow_w * + slow_avg) uo = 100 * weights / total_weight # Offset @@ -42,21 +61,19 @@ def uo(high, low, close, fast=None, medium=None, slow=None, fast_w=None, medium_ uo = uo.shift(offset) # Handle fills - if 'fillna' in kwargs: - uo.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - uo.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + uo.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + uo.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it uo.name = f"UO_{fast}_{medium}_{slow}" - uo.category = 'momentum' + uo.category = "momentum" return uo - -uo.__doc__ = \ -"""Ultimate Oscillator (UO) +uo.__doc__ = """Ultimate Oscillator (UO) The Ultimate Oscillator is a momentum indicator over three different periods. It attempts to correct false divergence trading signals. @@ -101,4 +118,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/momentum/willr.py b/pandas_ta/momentum/willr.py index 7702300..88ef6fd 100644 --- a/pandas_ta/momentum/willr.py +++ b/pandas_ta/momentum/willr.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from pandas_ta.utils import get_drift, get_offset, verify_series + def willr(high, low, close, length=None, offset=None, **kwargs): """Indicator: William's Percent R (WILLR)""" # Validate arguments @@ -8,7 +9,8 @@ def willr(high, low, close, length=None, offset=None, **kwargs): low = verify_series(low) close = verify_series(close) length = int(length) if length and length > 0 else 14 - min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) offset = get_offset(offset) # Calculate Result @@ -34,9 +36,7 @@ def willr(high, low, close, length=None, offset=None, **kwargs): return willr - -willr.__doc__ = \ -"""William's Percent R (WILLR) +willr.__doc__ = """William's Percent R (WILLR) William's Percent R is a momentum oscillator similar to the RSI that attempts to identify overbought and oversold conditions. @@ -65,4 +65,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/overlap/__init__.py b/pandas_ta/overlap/__init__.py index d7dbb1e..5a5ae90 100644 --- a/pandas_ta/overlap/__init__.py +++ b/pandas_ta/overlap/__init__.py @@ -25,4 +25,4 @@ from .vwap import vwap from .vwma import vwma from .wcp import wcp from .wma import wma -from .zlma import zlma \ No newline at end of file +from .zlma import zlma diff --git a/pandas_ta/overlap/dema.py b/pandas_ta/overlap/dema.py index 8102aa3..8adb345 100644 --- a/pandas_ta/overlap/dema.py +++ b/pandas_ta/overlap/dema.py @@ -2,6 +2,7 @@ from .ema import ema from pandas_ta.utils import get_offset, verify_series + def dema(close, length=None, offset=None, **kwargs): """Indicator: Double Exponential Moving Average (DEMA)""" # Validate Arguments @@ -25,9 +26,7 @@ def dema(close, length=None, offset=None, **kwargs): return dema - -dema.__doc__ = \ -"""Double Exponential Moving Average (DEMA) +dema.__doc__ = """Double Exponential Moving Average (DEMA) The Double Exponential Moving Average attempts to a smoother average with less lag than the normal Exponential Moving Average (EMA). @@ -55,4 +54,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/overlap/ema.py b/pandas_ta/overlap/ema.py index ccd77ca..06b9cab 100644 --- a/pandas_ta/overlap/ema.py +++ b/pandas_ta/overlap/ema.py @@ -2,15 +2,16 @@ from numpy import NaN as npNaN from ..utils import get_offset, verify_series + def ema(close, length=None, offset=None, **kwargs): """Indicator: Exponential Moving Average (EMA)""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 10 # min_periods = kwargs.pop('min_periods', length) - adjust = kwargs.pop('adjust', False) - sma = kwargs.pop('sma', True) - win_type = kwargs.pop('win_type', None) + adjust = kwargs.pop("adjust", False) + sma = kwargs.pop("sma", True) + win_type = kwargs.pop("win_type", None) offset = get_offset(offset) # Calculate Result @@ -27,14 +28,12 @@ def ema(close, length=None, offset=None, **kwargs): # Name & Category ema.name = f"EMA_{length}" - ema.category = 'overlap' + ema.category = "overlap" return ema - -ema.__doc__ = \ -"""Exponential Moving Average (EMA) +ema.__doc__ = """Exponential Moving Average (EMA) The Exponential Moving Average is more responsive moving average compared to the Simple Moving Average (SMA). The weights are determined by alpha which is @@ -68,4 +67,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/overlap/fwma.py b/pandas_ta/overlap/fwma.py index 61164c0..eedff2f 100644 --- a/pandas_ta/overlap/fwma.py +++ b/pandas_ta/overlap/fwma.py @@ -1,18 +1,21 @@ # -*- coding: utf-8 -*- from ..utils import fibonacci, get_offset, verify_series, weights + def fwma(close, length=None, asc=None, offset=None, **kwargs): """Indicator: Fibonacci's Weighted Moving Average (FWMA)""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 10 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) asc = asc if asc else True offset = get_offset(offset) - # Calculate Result + # Calculate Result fibs = fibonacci(n=length, weighted=True) - fwma = close.rolling(length, min_periods=length).apply(weights(fibs), raw=True) + fwma = close.rolling(length, min_periods=length).apply(weights(fibs), + raw=True) # Offset if offset != 0: @@ -20,14 +23,12 @@ def fwma(close, length=None, asc=None, offset=None, **kwargs): # Name & Category fwma.name = f"FWMA_{length}" - fwma.category = 'overlap' + fwma.category = "overlap" return fwma - -fwma.__doc__ = \ -"""Fibonacci's Weighted Moving Average (FWMA) +fwma.__doc__ = """Fibonacci's Weighted Moving Average (FWMA) Fibonacci's Weighted Moving Average is similar to a Weighted Moving Average (WMA) where the weights are based on the Fibonacci Sequence. @@ -36,7 +37,7 @@ Source: Kevin Johnson Calculation: Default Inputs: - length=10, + length=10, def weights(w): def _compute(x): @@ -58,4 +59,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/overlap/hilo.py b/pandas_ta/overlap/hilo.py index 0557892..3e041ef 100644 --- a/pandas_ta/overlap/hilo.py +++ b/pandas_ta/overlap/hilo.py @@ -6,7 +6,17 @@ from .hma import hma from .sma import sma from pandas_ta.utils import get_offset, verify_series -def hilo(high, low, close, high_length=None, low_length=None, mamode=None, offset=None, **kwargs): + +def hilo( + high, + low, + close, + high_length=None, + low_length=None, + mamode=None, + offset=None, + **kwargs, +): """Indicator: Gann HiLo (HiLo)""" # Validate Arguments high = verify_series(high) @@ -29,7 +39,7 @@ def hilo(high, low, close, high_length=None, low_length=None, mamode=None, offse if mamode == "hma": high_ma = hma(high, high_length) low_ma = hma(low, low_length) - else: # "sma" + else: # "sma" high_ma = sma(high, high_length) low_ma = sma(low, low_length) @@ -55,11 +65,14 @@ def hilo(high, low, close, high_length=None, low_length=None, mamode=None, offse # Name & Category _props = f"_{high_length}_{low_length}" - df = DataFrame({ - f"HILO{_props}": hilo, - f"HILOl{_props}": long, - f"HILOs{_props}": short - }, index=close.index) + df = DataFrame( + { + f"HILO{_props}": hilo, + f"HILOl{_props}": long, + f"HILOs{_props}": short + }, + index=close.index, + ) df.name = f"HILO{_props}" df.category = "overlap" @@ -67,9 +80,7 @@ def hilo(high, low, close, high_length=None, low_length=None, mamode=None, offse return df - -hilo.__doc__ = \ -"""Gann HiLo Activator(HiLo) +hilo.__doc__ = """Gann HiLo 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 diff --git a/pandas_ta/overlap/hl2.py b/pandas_ta/overlap/hl2.py index de79a73..358281c 100644 --- a/pandas_ta/overlap/hl2.py +++ b/pandas_ta/overlap/hl2.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, verify_series + def hl2(high, low, offset=None, **kwargs): """Indicator: HL2 """ # Validate Arguments @@ -17,6 +18,6 @@ def hl2(high, low, offset=None, **kwargs): # Name & Category hl2.name = "HL2" - hl2.category = 'overlap' + hl2.category = "overlap" - return hl2 \ No newline at end of file + return hl2 diff --git a/pandas_ta/overlap/hlc3.py b/pandas_ta/overlap/hlc3.py index 41a9a0e..3c3761f 100644 --- a/pandas_ta/overlap/hlc3.py +++ b/pandas_ta/overlap/hlc3.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, verify_series + def hlc3(high, low, close, offset=None, **kwargs): """Indicator: HLC3""" # Validate Arguments @@ -10,7 +11,7 @@ def hlc3(high, low, close, offset=None, **kwargs): offset = get_offset(offset) # Calculate Result - hlc3 = (high + low + close) / 3. + hlc3 = (high + low + close) / 3.0 # Offset if offset != 0: @@ -18,6 +19,6 @@ def hlc3(high, low, close, offset=None, **kwargs): # Name & Category hlc3.name = "HLC3" - hlc3.category = 'overlap' + hlc3.category = "overlap" - return hlc3 \ No newline at end of file + return hlc3 diff --git a/pandas_ta/overlap/hma.py b/pandas_ta/overlap/hma.py index 5e6b7f2..5fca866 100644 --- a/pandas_ta/overlap/hma.py +++ b/pandas_ta/overlap/hma.py @@ -3,12 +3,14 @@ from math import sqrt from .wma import wma from ..utils import get_offset, verify_series + def hma(close, length=None, offset=None, **kwargs): """Indicator: Hull Moving Average (HMA)""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 10 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) offset = get_offset(offset) # Calculate Result @@ -25,14 +27,12 @@ def hma(close, length=None, offset=None, **kwargs): # Name & Category hma.name = f"HMA_{length}" - hma.category = 'overlap' + hma.category = "overlap" return hma - -hma.__doc__ = \ -"""Hull Moving Average (HMA) +hma.__doc__ = """Hull Moving Average (HMA) The Hull Exponential Moving Average attempts to reduce or remove lag in moving averages. @@ -62,4 +62,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/overlap/ichimoku.py b/pandas_ta/overlap/ichimoku.py index c4fcb80..fa829d2 100644 --- a/pandas_ta/overlap/ichimoku.py +++ b/pandas_ta/overlap/ichimoku.py @@ -3,7 +3,15 @@ from pandas import date_range, DataFrame, RangeIndex, Timedelta from .midprice import midprice from ..utils import get_offset, verify_series -def ichimoku(high, low, close, tenkan=None, kijun=None, senkou=None, offset=None, **kwargs): + +def ichimoku(high, + low, + close, + tenkan=None, + kijun=None, + senkou=None, + offset=None, + **kwargs): """Indicator: Ichimoku Kinkō Hyō (Ichimoku)""" high = verify_series(high) low = verify_series(low) @@ -36,14 +44,14 @@ def ichimoku(high, low, close, tenkan=None, kijun=None, senkou=None, offset=None chikou_span = chikou_span.shift(offset) # Handle fills - if 'fillna' in kwargs: - span_a.fillna(kwargs['fillna'], inplace=True) - span_b.fillna(kwargs['fillna'], inplace=True) - chikou_span.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - span_a.fillna(method=kwargs['fill_method'], inplace=True) - span_b.fillna(method=kwargs['fill_method'], inplace=True) - chikou_span.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + span_a.fillna(kwargs["fillna"], inplace=True) + span_b.fillna(kwargs["fillna"], inplace=True) + chikou_span.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + span_a.fillna(method=kwargs["fill_method"], inplace=True) + span_b.fillna(method=kwargs["fill_method"], inplace=True) + chikou_span.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it span_a.name = f"ISA_{tenkan}" @@ -52,39 +60,43 @@ def ichimoku(high, low, close, tenkan=None, kijun=None, senkou=None, offset=None kijun_sen.name = f"IKS_{kijun}" chikou_span.name = f"ICS_{kijun}" - chikou_span.category = kijun_sen.category = tenkan_sen.category = 'trend' + chikou_span.category = kijun_sen.category = tenkan_sen.category = "trend" span_b.category = span_a.category = chikou_span # Prepare Ichimoku DataFrame - data = {span_a.name: span_a, span_b.name: span_b, tenkan_sen.name: tenkan_sen, kijun_sen.name: kijun_sen, chikou_span.name: chikou_span} + data = { + span_a.name: span_a, + span_b.name: span_b, + tenkan_sen.name: tenkan_sen, + kijun_sen.name: kijun_sen, + chikou_span.name: chikou_span, + } ichimokudf = DataFrame(data) ichimokudf.name = f"ICHIMOKU_{tenkan}_{kijun}_{senkou}" - ichimokudf.category = 'overlap' + ichimokudf.category = "overlap" # Prepare Span DataFrame last = close.index[-1] - if close.index.dtype == 'int64': + if close.index.dtype == "int64": ext_index = RangeIndex(start=last + 1, stop=last + kijun + 1) spandf = DataFrame(index=ext_index, columns=[span_a.name, span_b.name]) _span_a.index = _span_b.index = ext_index else: df_freq = close.index.value_counts().mode()[0] - tdelta = Timedelta(df_freq, unit='d') - new_dt = date_range(start=last + tdelta, periods=kijun, freq='B') + tdelta = Timedelta(df_freq, unit="d") + new_dt = date_range(start=last + tdelta, periods=kijun, freq="B") spandf = DataFrame(index=new_dt, columns=[span_a.name, span_b.name]) _span_a.index = _span_b.index = new_dt spandf[span_a.name] = _span_a spandf[span_b.name] = _span_b spandf.name = f"ICHISPAN_{tenkan}_{kijun}" - spandf.category = 'overlap' + spandf.category = "overlap" return ichimokudf, spandf - -ichimoku.__doc__ = \ -"""Ichimoku Kinkō Hyō (ichimoku) +ichimoku.__doc__ = """Ichimoku Kinkō Hyō (ichimoku) Developed Pre WWII as a forecasting model for financial markets. @@ -123,4 +135,4 @@ Returns: For the visible period: spanA, spanB, tenkan_sen, kijun_sen, and chikou_span columns For the forward looking period: spanA and spanB columns -""" \ No newline at end of file +""" diff --git a/pandas_ta/overlap/kama.py b/pandas_ta/overlap/kama.py index 3ad3095..9dedcaf 100644 --- a/pandas_ta/overlap/kama.py +++ b/pandas_ta/overlap/kama.py @@ -3,7 +3,14 @@ from numpy import NaN as npNaN from pandas import Series, DataFrame from ..utils import get_drift, get_offset, non_zero_range, verify_series -def kama(close, length=None, fast=None, slow=None, drift=None, offset=None, **kwargs): + +def kama(close, + length=None, + fast=None, + slow=None, + drift=None, + offset=None, + **kwargs): """Indicator: Kaufman's Adaptive Moving Average (HMA)""" # Validate Arguments close = verify_series(close) @@ -15,6 +22,7 @@ def kama(close, length=None, fast=None, slow=None, drift=None, offset=None, **kw # Calculate Result m = close.size + def weight(length: int) -> float: return 2 / (length + 1) @@ -31,7 +39,7 @@ def kama(close, length=None, fast=None, slow=None, drift=None, offset=None, **kw result = [npNaN for _ in range(0, length - 1)] + [0] for i in range(length, m): result.append(sc[i] * close[i] + (1 - sc[i]) * result[i - 1]) - + kama = Series(result, index=close.index) # Offset @@ -45,9 +53,7 @@ def kama(close, length=None, fast=None, slow=None, drift=None, offset=None, **kw return kama - -kama.__doc__ = \ -"""Kaufman's Adaptive Moving Average (KAMA) +kama.__doc__ = """Kaufman's Adaptive Moving Average (KAMA) Developed by Perry Kaufman, Kaufman's Adaptive Moving Average (KAMA) is a moving average designed to account for market noise or volatility. KAMA will closely follow prices when @@ -76,4 +82,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/overlap/linreg.py b/pandas_ta/overlap/linreg.py index d1bdc1d..d4d8b22 100644 --- a/pandas_ta/overlap/linreg.py +++ b/pandas_ta/overlap/linreg.py @@ -2,12 +2,14 @@ import math from pandas_ta.utils import get_offset, verify_series + def linreg(close, length=None, offset=None, **kwargs): """Indicator: Linear Regression""" # Validate arguments close = verify_series(close) length = int(length) if length and length > 0 else 14 - min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) offset = get_offset(offset) angle = kwargs.pop("angle", False) intercept = kwargs.pop("intercept", False) @@ -17,7 +19,7 @@ def linreg(close, length=None, offset=None, **kwargs): tsf = kwargs.pop("tsf", False) # Calculate Result - x = range(1, length + 1) # [1, 2, ..., n] from 1 to n keeps Sum(xy) low + x = range(1, length + 1) # [1, 2, ..., n] from 1 to n keeps Sum(xy) low x_sum = 0.5 * length * (length + 1) x2_sum = x_sum * (2 * length + 1) / 3 divisor = length * x2_sum - x_sum * x_sum @@ -38,7 +40,7 @@ def linreg(close, length=None, offset=None, **kwargs): if degrees: theta *= 180 / math.pi return theta - + if r: y2_sum = (series * series).sum() rn = length * xy_sum - x_sum * y_sum @@ -47,7 +49,8 @@ def linreg(close, length=None, offset=None, **kwargs): return m * length + b if tsf else m * (length - 1) + b - linreg = close.rolling(length, min_periods=length).apply(linear_regression, raw=False) + linreg = close.rolling(length, min_periods=length).apply(linear_regression, + raw=False) # Offset if offset != 0: @@ -61,19 +64,21 @@ def linreg(close, length=None, offset=None, **kwargs): # Name and Categorize it linreg.name = f"LR" - if slope: linreg.name += "m" - if intercept: linreg.name += "b" - if angle: linreg.name += "a" - if r: linreg.name += "r" + if slope: + linreg.name += "m" + if intercept: + linreg.name += "b" + if angle: + linreg.name += "a" + if r: + linreg.name += "r" linreg.name += f"_{length}" linreg.category = "overlap" return linreg - -linreg.__doc__ = \ -"""Linear Regression Moving Average (linreg) +linreg.__doc__ = """Linear Regression Moving Average (linreg) Linear Regression Moving Average (LINREG). This is a simplified version of a Standard Linear Regression. LINREG is a rolling regression of one variable. A @@ -117,4 +122,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/overlap/midpoint.py b/pandas_ta/overlap/midpoint.py index 83d69d0..b4634cc 100644 --- a/pandas_ta/overlap/midpoint.py +++ b/pandas_ta/overlap/midpoint.py @@ -1,12 +1,14 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, verify_series + def midpoint(close, length=None, offset=None, **kwargs): """Indicator: Midpoint""" # Validate arguments close = verify_series(close) length = int(length) if length and length > 0 else 2 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) offset = get_offset(offset) # Calculate Result @@ -19,13 +21,13 @@ def midpoint(close, length=None, offset=None, **kwargs): midpoint = midpoint.shift(offset) # Handle fills - if 'fillna' in kwargs: - midpoint.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - midpoint.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + midpoint.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + midpoint.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it midpoint.name = f"MIDPOINT_{length}" - midpoint.category = 'overlap' + midpoint.category = "overlap" - return midpoint \ No newline at end of file + return midpoint diff --git a/pandas_ta/overlap/midprice.py b/pandas_ta/overlap/midprice.py index e6cda9a..6d8ff66 100644 --- a/pandas_ta/overlap/midprice.py +++ b/pandas_ta/overlap/midprice.py @@ -1,13 +1,15 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, verify_series + def midprice(high, low, length=None, offset=None, **kwargs): """Indicator: Midprice""" # Validate arguments high = verify_series(high) low = verify_series(low) length = int(length) if length and length > 0 else 2 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) offset = get_offset(offset) # Calculate Result @@ -20,13 +22,13 @@ def midprice(high, low, length=None, offset=None, **kwargs): midprice = midprice.shift(offset) # Handle fills - if 'fillna' in kwargs: - midprice.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - midprice.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + midprice.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + midprice.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it midprice.name = f"MIDPRICE_{length}" - midprice.category = 'overlap' + midprice.category = "overlap" - return midprice \ No newline at end of file + return midprice diff --git a/pandas_ta/overlap/ohlc4.py b/pandas_ta/overlap/ohlc4.py index 8a18488..788a499 100644 --- a/pandas_ta/overlap/ohlc4.py +++ b/pandas_ta/overlap/ohlc4.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, verify_series + def ohlc4(open_, high, low, close, offset=None, **kwargs): """Indicator: OHLC4""" # Validate Arguments @@ -19,6 +20,6 @@ def ohlc4(open_, high, low, close, offset=None, **kwargs): # Name & Category ohlc4.name = "OHLC4" - ohlc4.category = 'overlap' + ohlc4.category = "overlap" - return ohlc4 \ No newline at end of file + return ohlc4 diff --git a/pandas_ta/overlap/pwma.py b/pandas_ta/overlap/pwma.py index 2ae589f..8535b13 100644 --- a/pandas_ta/overlap/pwma.py +++ b/pandas_ta/overlap/pwma.py @@ -1,18 +1,21 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, pascals_triangle, verify_series, weights + def pwma(close, length=None, asc=None, offset=None, **kwargs): """Indicator: Pascals Weighted Moving Average (PWMA)""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 10 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) asc = asc if asc else True offset = get_offset(offset) # Calculate Result triangle = pascals_triangle(n=length - 1, weighted=True) - pwma = close.rolling(length, min_periods=length).apply(weights(triangle), raw=True) + pwma = close.rolling(length, min_periods=length).apply(weights(triangle), + raw=True) # Offset if offset != 0: @@ -20,14 +23,12 @@ def pwma(close, length=None, asc=None, offset=None, **kwargs): # Name & Category pwma.name = f"PWMA_{length}" - pwma.category = 'overlap' + pwma.category = "overlap" return pwma - -pwma.__doc__ = \ -"""Pascal's Weighted Moving Average (PWMA) +pwma.__doc__ = """Pascal's Weighted Moving Average (PWMA) Pascal's Weighted Moving Average is similar to a symmetric triangular window except PWMA's weights are based on Pascal's Triangle. @@ -58,4 +59,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/overlap/rma.py b/pandas_ta/overlap/rma.py index 5a22870..528bdb7 100644 --- a/pandas_ta/overlap/rma.py +++ b/pandas_ta/overlap/rma.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, verify_series + def rma(close, length=None, offset=None, **kwargs): """Indicator: wildeR's Moving Average (RMA)""" # Validate Arguments @@ -23,9 +24,7 @@ def rma(close, length=None, offset=None, **kwargs): return rma - -rma.__doc__ = \ -"""wildeR's Moving Average (RMA) +rma.__doc__ = """wildeR's Moving Average (RMA) The WildeR's Moving Average is simply an Exponential Moving Average (EMA) with a modified alpha = 1 / length. @@ -51,4 +50,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/overlap/sinwma.py b/pandas_ta/overlap/sinwma.py index b78aec0..af736d6 100644 --- a/pandas_ta/overlap/sinwma.py +++ b/pandas_ta/overlap/sinwma.py @@ -4,19 +4,22 @@ from math import sin from pandas import Series from ..utils import get_offset, pascals_triangle, verify_series, weights + def sinwma(close, length=None, asc=None, offset=None, **kwargs): """Indicator: Sine Weighted Moving Average (SINWMA) by Everget of TradingView""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 14 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) offset = get_offset(offset) # Calculate Result sines = Series([sin((i + 1) * pi / (length + 1)) for i in range(0, length)]) w = sines / sines.sum() - sinwma = close.rolling(length, min_periods=length).apply(weights(w), raw=True) + sinwma = close.rolling(length, min_periods=length).apply(weights(w), + raw=True) # Offset if offset != 0: @@ -24,14 +27,12 @@ def sinwma(close, length=None, asc=None, offset=None, **kwargs): # Name & Category sinwma.name = f"SINWMA_{length}" - sinwma.category = 'overlap' + sinwma.category = "overlap" return sinwma - -sinwma.__doc__ = \ -"""Sine Weighted Moving Average (SWMA) +sinwma.__doc__ = """Sine Weighted Moving Average (SWMA) A weighted average using sine cycles. The middle term(s) of the average have the highest weight(s). @@ -64,4 +65,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/overlap/sma.py b/pandas_ta/overlap/sma.py index ea49511..8b2b8f9 100644 --- a/pandas_ta/overlap/sma.py +++ b/pandas_ta/overlap/sma.py @@ -1,12 +1,14 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, verify_series + def sma(close, length=None, offset=None, **kwargs): """Indicator: Simple Moving Average (SMA)""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 10 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) offset = get_offset(offset) # Calculate Result @@ -15,23 +17,21 @@ def sma(close, length=None, offset=None, **kwargs): # Offset if offset != 0: sma = sma.shift(offset) - + # Handle fills - if 'fillna' in kwargs: - sma.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - sma.fillna(method=kwargs['fill_method'], inplace=True) + if "fillna" in kwargs: + sma.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + sma.fillna(method=kwargs["fill_method"], inplace=True) # Name & Category sma.name = f"SMA_{length}" - sma.category = 'overlap' + sma.category = "overlap" return sma - -sma.__doc__ = \ -"""Simple Moving Average (SMA) +sma.__doc__ = """Simple Moving Average (SMA) The Simple Moving Average is the classic moving average that is the equally weighted average over n periods. diff --git a/pandas_ta/overlap/supertrend.py b/pandas_ta/overlap/supertrend.py index 3ff86d4..9393bb1 100644 --- a/pandas_ta/overlap/supertrend.py +++ b/pandas_ta/overlap/supertrend.py @@ -6,14 +6,20 @@ from pandas_ta.volatility import atr from pandas_ta.utils import get_offset, verify_series -def supertrend(high, low, close, length=None, multiplier=None, offset=None, **kwargs): +def supertrend(high, + low, + close, + length=None, + multiplier=None, + offset=None, + **kwargs): """Indicator: Supertrend""" # Validate Arguments high = verify_series(high) low = verify_series(low) close = verify_series(close) length = int(length) if length and length > 0 else 7 - multiplier = float(multiplier) if multiplier and multiplier > 0 else 3. + multiplier = float(multiplier) if multiplier and multiplier > 0 else 3.0 offset = get_offset(offset) # Calculate Results @@ -37,7 +43,7 @@ def supertrend(high, low, close, length=None, multiplier=None, offset=None, **kw lowerband.iloc[i] = lowerband.iloc[i - 1] if dir_[i] < 0 and upperband.iloc[i] > upperband.iloc[i - 1]: upperband.iloc[i] = upperband.iloc[i - 1] - + if dir_[i] > 0: trend[i] = long[i] = lowerband.iloc[i] else: @@ -45,12 +51,15 @@ def supertrend(high, low, close, length=None, multiplier=None, offset=None, **kw # Prepare DataFrame to return _props = f"_{length}_{multiplier}" - df = DataFrame({ - f"SUPERT{_props}": trend, - f"SUPERTd{_props}": dir_, - f"SUPERTl{_props}": long, - f"SUPERTs{_props}": short - }, index=close.index) + df = DataFrame( + { + f"SUPERT{_props}": trend, + f"SUPERTd{_props}": dir_, + f"SUPERTl{_props}": long, + f"SUPERTs{_props}": short, + }, + index=close.index, + ) df.name = f"SUPERT{_props}" df.category = "overlap" @@ -69,8 +78,7 @@ def supertrend(high, low, close, length=None, multiplier=None, offset=None, **kw return df -supertrend.__doc__ = \ -"""Supertrend (supertrend) +supertrend.__doc__ = """Supertrend (supertrend) Supertrend is an overlap indicator. It is used to help identify trend direction, setting stop loss, identify support and resistance, and/or diff --git a/pandas_ta/overlap/swma.py b/pandas_ta/overlap/swma.py index 3776aab..765f45a 100644 --- a/pandas_ta/overlap/swma.py +++ b/pandas_ta/overlap/swma.py @@ -1,18 +1,21 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, symmetric_triangle, verify_series, weights + def swma(close, length=None, asc=None, offset=None, **kwargs): """Indicator: Symmetric Weighted Moving Average (SWMA)""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 10 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) asc = asc if asc else True offset = get_offset(offset) # Calculate Result triangle = symmetric_triangle(length, weighted=True) - swma = close.rolling(length, min_periods=length).apply(weights(triangle), raw=True) + swma = close.rolling(length, min_periods=length).apply(weights(triangle), + raw=True) # Offset if offset != 0: @@ -20,20 +23,18 @@ def swma(close, length=None, asc=None, offset=None, **kwargs): # Name & Category swma.name = f"SWMA_{length}" - swma.category = 'overlap' + swma.category = "overlap" return swma - -swma.__doc__ = \ -"""Symmetric Weighted Moving Average (SWMA) +swma.__doc__ = """Symmetric Weighted Moving Average (SWMA) Symmetric Weighted Moving Average where weights are based on a symmetric triangle. For example: n=3 -> [1, 2, 1], n=4 -> [1, 2, 2, 1], etc... This moving average has variable length in contrast to TradingView's fixed length of 4. -Source: +Source: https://www.tradingview.com/study-script-reference/#fun_swma Calculation: @@ -60,4 +61,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/overlap/t3.py b/pandas_ta/overlap/t3.py index ed47c19..19124ee 100644 --- a/pandas_ta/overlap/t3.py +++ b/pandas_ta/overlap/t3.py @@ -2,20 +2,22 @@ from .ema import ema from ..utils import get_offset, verify_series + def t3(close, length=None, a=None, offset=None, **kwargs): """Indicator: T3""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 10 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) a = float(a) if a and a > 0 and a < 1 else 0.7 offset = get_offset(offset) # Calculate Result - c1 = -a * a ** 2 - c2 = 3 * a ** 2 + 3 * a ** 3 - c3 = -6 * a ** 2 - 3 * a - 3 * a ** 3 - c4 = a ** 3 + 3 * a ** 2 + 3 * a + 1 + c1 = -a * a**2 + c2 = 3 * a**2 + 3 * a**3 + c3 = -6 * a**2 - 3 * a - 3 * a**3 + c4 = a**3 + 3 * a**2 + 3 * a + 1 e1 = ema(close=close, length=length, **kwargs) e2 = ema(close=e1, length=length, **kwargs) @@ -31,14 +33,12 @@ def t3(close, length=None, a=None, offset=None, **kwargs): # Name & Category t3.name = f"T3_{length}_{a}" - t3.category = 'overlap' + t3.category = "overlap" return t3 - -t3.__doc__ = \ -"""Tim Tillson's T3 Moving Average (T3) +t3.__doc__ = """Tim Tillson's T3 Moving Average (T3) Tim Tillson's T3 Moving Average is considered a smoother and more responsive moving average relative to other moving averages. @@ -76,4 +76,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/overlap/tema.py b/pandas_ta/overlap/tema.py index 1581b8e..3039845 100644 --- a/pandas_ta/overlap/tema.py +++ b/pandas_ta/overlap/tema.py @@ -2,12 +2,14 @@ from .ema import ema from ..utils import get_offset, verify_series + def tema(close, length=None, offset=None, **kwargs): """Indicator: Triple Exponential Moving Average (TEMA)""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 10 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) offset = get_offset(offset) # Calculate Result @@ -22,14 +24,12 @@ def tema(close, length=None, offset=None, **kwargs): # Name & Category tema.name = f"TEMA_{length}" - tema.category = 'overlap' + tema.category = "overlap" return tema - -tema.__doc__ = \ -"""Triple Exponential Moving Average (TEMA) +tema.__doc__ = """Triple Exponential Moving Average (TEMA) A less laggy Exponential Moving Average. @@ -58,4 +58,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/overlap/trima.py b/pandas_ta/overlap/trima.py index 369c252..14a88a6 100644 --- a/pandas_ta/overlap/trima.py +++ b/pandas_ta/overlap/trima.py @@ -1,12 +1,14 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, verify_series + def trima(close, length=None, offset=None, **kwargs): """Indicator: Triangular Moving Average (TRIMA)""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 10 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) offset = get_offset(offset) # Calculate Result @@ -20,14 +22,12 @@ def trima(close, length=None, offset=None, **kwargs): # Name & Category trima.name = f"TRIMA_{length}" - trima.category = 'overlap' + trima.category = "overlap" return trima - -trima.__doc__ = \ -"""Triangular Moving Average (TRIMA) +trima.__doc__ = """Triangular Moving Average (TRIMA) A weighted moving average where the shape of the weights are triangular and the greatest weight is in the middle of the period. @@ -57,4 +57,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/overlap/vwap.py b/pandas_ta/overlap/vwap.py index 3401377..e2f4041 100644 --- a/pandas_ta/overlap/vwap.py +++ b/pandas_ta/overlap/vwap.py @@ -2,6 +2,7 @@ from .hlc3 import hlc3 from ..utils import get_offset, is_datetime_ordered, verify_series + def vwap(high, low, close, volume, offset=None, **kwargs): """Indicator: Volume Weighted Average Price (VWAP)""" # Validate Arguments @@ -12,7 +13,9 @@ def vwap(high, low, close, volume, offset=None, **kwargs): offset = get_offset(offset) if not is_datetime_ordered(volume): - print(f"[!] VWAP volume series is not datetime ordered. Results may not be as expected.") + print( + f"[!] VWAP volume series is not datetime ordered. Results may not be as expected." + ) # Calculate Result tp = hlc3(high=high, low=low, close=close) @@ -29,9 +32,7 @@ def vwap(high, low, close, volume, offset=None, **kwargs): return vwap - -vwap.__doc__ = \ -"""Volume Weighted Average Price (VWAP) +vwap.__doc__ = """Volume Weighted Average Price (VWAP) The Volume Weighted Average Price that measures the average typical price by volume. It is typically used with intraday charts to identify general diff --git a/pandas_ta/overlap/vwma.py b/pandas_ta/overlap/vwma.py index b2b06d3..7065f59 100644 --- a/pandas_ta/overlap/vwma.py +++ b/pandas_ta/overlap/vwma.py @@ -2,6 +2,7 @@ from .sma import sma from ..utils import get_offset, verify_series + def vwma(close, volume, length=None, offset=None, **kwargs): """Indicator: Volume Weighted Moving Average (VWMA)""" # Validate Arguments @@ -20,14 +21,12 @@ def vwma(close, volume, length=None, offset=None, **kwargs): # Name & Category vwma.name = f"VWMA_{length}" - vwma.category = 'overlap' + vwma.category = "overlap" return vwma - -vwma.__doc__ = \ -"""Volume Weighted Moving Average (VWMA) +vwma.__doc__ = """Volume Weighted Moving Average (VWMA) Volume Weighted Moving Average. @@ -53,4 +52,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/overlap/wcp.py b/pandas_ta/overlap/wcp.py index 6e9dbc7..05e871b 100644 --- a/pandas_ta/overlap/wcp.py +++ b/pandas_ta/overlap/wcp.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, verify_series + def wcp(high, low, close, offset=None, **kwargs): """Indicator: Weighted Closing Price (WCP)""" # Validate Arguments @@ -18,14 +19,12 @@ def wcp(high, low, close, offset=None, **kwargs): # Name & Category wcp.name = "WCP" - wcp.category = 'overlap' + wcp.category = "overlap" return wcp - -wcp.__doc__ = \ -"""Weighted Closing Price (WCP) +wcp.__doc__ = """Weighted Closing Price (WCP) Weighted Closing Price is the weighted price given: high, low and double the close. @@ -48,4 +47,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/overlap/wma.py b/pandas_ta/overlap/wma.py index 2ca16a9..993c905 100644 --- a/pandas_ta/overlap/wma.py +++ b/pandas_ta/overlap/wma.py @@ -4,12 +4,14 @@ from numpy import dot as npdot from pandas import Series from ..utils import get_offset, verify_series + def wma(close, length=None, asc=None, offset=None, **kwargs): """Indicator: Weighted Moving Average (WMA)""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 10 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) asc = asc if asc else True offset = get_offset(offset) @@ -19,8 +21,10 @@ def wma(close, length=None, asc=None, offset=None, **kwargs): weights = weights_ if asc else weights_[::-1] def linear(w): + def _compute(x): return npdot(x, w) / total_weight + return _compute close_ = close.rolling(length, min_periods=length) @@ -32,14 +36,12 @@ def wma(close, length=None, asc=None, offset=None, **kwargs): # Name & Category wma.name = f"WMA_{length}" - wma.category = 'overlap' + wma.category = "overlap" return wma - -wma.__doc__ = \ -"""Weighted Moving Average (WMA) +wma.__doc__ = """Weighted Moving Average (WMA) The Weighted Moving Average where the weights are linearly increasing and the most recent data has the heaviest weight. diff --git a/pandas_ta/overlap/zlma.py b/pandas_ta/overlap/zlma.py index f9c7f69..212f665 100644 --- a/pandas_ta/overlap/zlma.py +++ b/pandas_ta/overlap/zlma.py @@ -6,12 +6,14 @@ from .sma import sma from .wma import wma from ..utils import get_offset, verify_series + def zlma(close, length=None, mamode=None, offset=None, **kwargs): """Indicator: Zero Lag Moving Average (ZLMA)""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 10 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) offset = get_offset(offset) mamode = mamode.lower() if mamode else None @@ -19,15 +21,15 @@ def zlma(close, length=None, mamode=None, offset=None, **kwargs): lag = int(0.5 * (length - 1)) close = 2 * close - close.shift(lag) - if mamode is None or mamode == 'ema': + if mamode is None or mamode == "ema": zlma = ema(close, length=length, **kwargs) - if mamode == 'hma': + if mamode == "hma": zlma = hma(close, length=length, **kwargs) - if mamode == 'rma': + if mamode == "rma": zlma = rma(close, length=length, **kwargs) - if mamode == 'sma': + if mamode == "sma": zlma = sma(close, length=length, **kwargs) - if mamode == 'wma': + if mamode == "wma": zlma = wma(close, length=length, **kwargs) # Offset @@ -36,14 +38,12 @@ def zlma(close, length=None, mamode=None, offset=None, **kwargs): # Name & Category zlma.name = f"ZL_{zlma.name}" - zlma.category = 'overlap' + zlma.category = "overlap" return zlma - -zlma.__doc__ = \ -"""Zero Lag Moving Average (ZLMA) +zlma.__doc__ = """Zero Lag Moving Average (ZLMA) The Zero Lag Moving Average attempts to eliminate the lag associated with moving averages. This is an adaption created by John Ehler and Ric Way. @@ -72,4 +72,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/performance/__init__.py b/pandas_ta/performance/__init__.py index 53862ee..f8b7ea9 100644 --- a/pandas_ta/performance/__init__.py +++ b/pandas_ta/performance/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- from .log_return import log_return from .percent_return import percent_return -from .trend_return import trend_return \ No newline at end of file +from .trend_return import trend_return diff --git a/pandas_ta/performance/log_return.py b/pandas_ta/performance/log_return.py index 7c251a8..b22e66d 100644 --- a/pandas_ta/performance/log_return.py +++ b/pandas_ta/performance/log_return.py @@ -2,6 +2,7 @@ from numpy import log as nplog from pandas_ta.utils import get_offset, verify_series + def log_return(close, length=None, cumulative=False, offset=None, **kwargs): """Indicator: Log Return""" # Validate Arguments @@ -18,13 +19,13 @@ def log_return(close, length=None, cumulative=False, offset=None, **kwargs): # Offset if offset != 0: log_return = log_return.shift(offset) - + # Handle fills if "fillna" in kwargs: log_return.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: log_return.fillna(method=kwargs["fill_method"], inplace=True) - + # Name & Category log_return.name = f"{'CUM' if cumulative else ''}LOGRET_{length}" log_return.category = "performance" @@ -32,9 +33,7 @@ def log_return(close, length=None, cumulative=False, offset=None, **kwargs): return log_return - -log_return.__doc__ = \ -"""Log Return +log_return.__doc__ = """Log Return Calculates the logarithmic return of a Series. See also: help(df.ta.log_return) for additional **kwargs a valid 'df'. diff --git a/pandas_ta/performance/percent_return.py b/pandas_ta/performance/percent_return.py index 4a325e2..b7954a6 100644 --- a/pandas_ta/performance/percent_return.py +++ b/pandas_ta/performance/percent_return.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from pandas_ta.utils import get_offset, verify_series + def percent_return(close, length=None, cumulative=False, offset=None, **kwargs): """Indicator: Percent Return""" # Validate Arguments @@ -25,9 +26,7 @@ def percent_return(close, length=None, cumulative=False, offset=None, **kwargs): return pct_return - -percent_return.__doc__ = \ -"""Percent Return +percent_return.__doc__ = """Percent Return Calculates the percent return of a Series. See also: help(df.ta.percent_return) for additional **kwargs a valid 'df'. @@ -53,4 +52,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/performance/trend_return.py b/pandas_ta/performance/trend_return.py index aba6e7b..56b6bc2 100644 --- a/pandas_ta/performance/trend_return.py +++ b/pandas_ta/performance/trend_return.py @@ -4,13 +4,22 @@ from .log_return import log_return from .percent_return import percent_return from pandas_ta.utils import get_offset, verify_series, zero -def trend_return(close, trend, log=True, cumulative=None, trend_reset=0, offset=None, **kwargs): + +def trend_return(close, + trend, + log=True, + cumulative=None, + trend_reset=0, + offset=None, + **kwargs): """Indicator: Trend Return""" # Validate Arguments close = verify_series(close) trend = verify_series(trend) - cumulative = cumulative if cumulative is not None and isinstance(cumulative, bool) else False - trend_reset = int(trend_reset) if trend_reset and isinstance(trend_reset, int) else 0 + cumulative = (cumulative if cumulative is not None and + isinstance(cumulative, bool) else False) + trend_reset = (int(trend_reset) + if trend_reset and isinstance(trend_reset, int) else 0) offset = get_offset(offset) # Calculate Result @@ -20,7 +29,7 @@ def trend_return(close, trend, log=True, cumulative=None, trend_reset=0, offset= returns = percent_return(close, cumulative=False) trends = trend.astype(int) returns = (trends * returns).apply(zero) - + tsum = 0 m = trends.size result = [] @@ -39,12 +48,15 @@ def trend_return(close, trend, log=True, cumulative=None, trend_reset=0, offset= _log = "L" if log else "P" _returns = "LOGRET" if log else "PCTRET" _props = f"{_cumulative}{_log}TR" - df = DataFrame({ - _props: result, - f"TR_{_returns}": returns, - f"{_props}_Trends": trends, - f"{_props}_Trades": trends.diff().shift(1).fillna(0).astype(int), - }, index=close.index) + df = DataFrame( + { + _props: result, + f"TR_{_returns}": returns, + f"{_props}_Trends": trends, + f"{_props}_Trades": trends.diff().shift(1).fillna(0).astype(int), + }, + index=close.index, + ) # Offset if offset != 0: @@ -57,8 +69,7 @@ def trend_return(close, trend, log=True, cumulative=None, trend_reset=0, offset= return df -trend_return.__doc__ = \ -"""Trend Return +trend_return.__doc__ = """Trend Return Calculates the (Cumulative) Returns of a Trend as defined by a sequence of booleans called a 'trend'. One popular example in TA literature is to be long when the 'close' > 'moving average'. In which case, the trend= close > sma(close, 50). By default it calculates log returns but can also use percent change. @@ -107,4 +118,4 @@ Kwargs: Returns: pd.DataFrame: Returns columns: Trend Return, Close Return, Trends, and Trades (Enter: 1, Exit: -1, Otherwise: 0). -""" \ No newline at end of file +""" diff --git a/pandas_ta/statistics/__init__.py b/pandas_ta/statistics/__init__.py index 57c3fb3..b7d8202 100644 --- a/pandas_ta/statistics/__init__.py +++ b/pandas_ta/statistics/__init__.py @@ -7,4 +7,4 @@ from .quantile import quantile from .skew import skew from .stdev import stdev from .variance import variance -from .zscore import zscore \ No newline at end of file +from .zscore import zscore diff --git a/pandas_ta/statistics/entropy.py b/pandas_ta/statistics/entropy.py index 216833d..0d61bc4 100644 --- a/pandas_ta/statistics/entropy.py +++ b/pandas_ta/statistics/entropy.py @@ -2,12 +2,13 @@ from numpy import log as npLog from ..utils import get_offset, verify_series + def entropy(close, length=None, base=None, offset=None, **kwargs): """Indicator: Entropy (ENTP)""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 10 - base = float(base) if base and base > 0 else 2. + base = float(base) if base and base > 0 else 2.0 offset = get_offset(offset) # Calculate Result @@ -25,9 +26,7 @@ def entropy(close, length=None, base=None, offset=None, **kwargs): return entropy - -entropy.__doc__ = \ -"""Entropy (ENTP) +entropy.__doc__ = """Entropy (ENTP) Introduced by Claude Shannon in 1948, entropy measures the unpredictability of the data, or equivalently, of its average information. A die has higher @@ -39,7 +38,7 @@ Sources: Calculation: Default Inputs: length=10, base=2 - + P = close / SUM(close, length) E = SUM(-P * npLog(P) / npLog(base), length) @@ -55,4 +54,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/statistics/kurtosis.py b/pandas_ta/statistics/kurtosis.py index 4b6fa82..b0af952 100644 --- a/pandas_ta/statistics/kurtosis.py +++ b/pandas_ta/statistics/kurtosis.py @@ -1,12 +1,14 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, verify_series + def kurtosis(close, length=None, offset=None, **kwargs): """Indicator: Kurtosis""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 30 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) offset = get_offset(offset) # Calculate Result @@ -23,9 +25,7 @@ def kurtosis(close, length=None, offset=None, **kwargs): return kurtosis - -kurtosis.__doc__ = \ -"""Rolling Kurtosis +kurtosis.__doc__ = """Rolling Kurtosis Sources: @@ -45,4 +45,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/statistics/mad.py b/pandas_ta/statistics/mad.py index a355717..892603a 100644 --- a/pandas_ta/statistics/mad.py +++ b/pandas_ta/statistics/mad.py @@ -2,12 +2,14 @@ from numpy import fabs as npfabs from ..utils import get_offset, verify_series + def mad(close, length=None, offset=None, **kwargs): """Indicator: Mean Absolute Deviation""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 30 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) offset = get_offset(offset) # Calculate Result @@ -28,9 +30,7 @@ def mad(close, length=None, offset=None, **kwargs): return mad - -mad.__doc__ = \ -"""Rolling Mean Absolute Deviation +mad.__doc__ = """Rolling Mean Absolute Deviation Sources: @@ -50,4 +50,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/statistics/median.py b/pandas_ta/statistics/median.py index dcf43c6..86ca24a 100644 --- a/pandas_ta/statistics/median.py +++ b/pandas_ta/statistics/median.py @@ -1,12 +1,14 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, verify_series + def median(close, length=None, offset=None, **kwargs): """Indicator: Median""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 30 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) offset = get_offset(offset) # Calculate Result @@ -23,9 +25,7 @@ def median(close, length=None, offset=None, **kwargs): return median - -median.__doc__ = \ -"""Rolling Median +median.__doc__ = """Rolling Median Rolling Median of over 'n' periods. Sibling of a Simple Moving Average. @@ -48,4 +48,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/statistics/quantile.py b/pandas_ta/statistics/quantile.py index 30a81b0..d9c5439 100644 --- a/pandas_ta/statistics/quantile.py +++ b/pandas_ta/statistics/quantile.py @@ -1,12 +1,14 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, verify_series + def quantile(close, length=None, q=None, offset=None, **kwargs): """Indicator: Quantile""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 30 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) q = float(q) if q and q > 0 and q < 1 else 0.5 offset = get_offset(offset) @@ -24,9 +26,7 @@ def quantile(close, length=None, q=None, offset=None, **kwargs): return quantile - -quantile.__doc__ = \ -"""Rolling Quantile +quantile.__doc__ = """Rolling Quantile Sources: @@ -47,4 +47,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/statistics/skew.py b/pandas_ta/statistics/skew.py index dbed0d4..fc2c6c1 100644 --- a/pandas_ta/statistics/skew.py +++ b/pandas_ta/statistics/skew.py @@ -1,12 +1,14 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, verify_series + def skew(close, length=None, offset=None, **kwargs): """Indicator: Skew""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 30 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) offset = get_offset(offset) # Calculate Result @@ -15,13 +17,13 @@ def skew(close, length=None, offset=None, **kwargs): # Offset if offset != 0: skew = skew.shift(offset) - + # Handle fills - if 'fillna' in kwargs: - skew.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - skew.fillna(method=kwargs['fill_method'], inplace=True) - + if "fillna" in kwargs: + skew.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + skew.fillna(method=kwargs["fill_method"], inplace=True) + # Name & Category skew.name = f"SKEW_{length}" skew.category = "statistics" @@ -29,9 +31,7 @@ def skew(close, length=None, offset=None, **kwargs): return skew - -skew.__doc__ = \ -"""Rolling Skew +skew.__doc__ = """Rolling Skew Sources: diff --git a/pandas_ta/statistics/stdev.py b/pandas_ta/statistics/stdev.py index d89561d..c72b756 100644 --- a/pandas_ta/statistics/stdev.py +++ b/pandas_ta/statistics/stdev.py @@ -3,6 +3,7 @@ from numpy import sqrt as npsqrt from .variance import variance from ..utils import get_offset, verify_series + def stdev(close, length=None, ddof=1, offset=None, **kwargs): """Indicator: Standard Deviation""" # Validate Arguments @@ -25,9 +26,7 @@ def stdev(close, length=None, ddof=1, offset=None, **kwargs): return stdev - -stdev.__doc__ = \ -"""Rolling Standard Deviation +stdev.__doc__ = """Rolling Standard Deviation Sources: @@ -40,9 +39,9 @@ Calculation: Args: close (pd.Series): Series of 'close's length (int): It's period. Default: 30 - ddof (int): Delta Degrees of Freedom. - The divisor used in calculations is N - ddof, - where N represents the number of elements. Default: 1 + ddof (int): Delta Degrees of Freedom. + The divisor used in calculations is N - ddof, + where N represents the number of elements. Default: 1 offset (int): How many periods to offset the result. Default: 0 Kwargs: diff --git a/pandas_ta/statistics/variance.py b/pandas_ta/statistics/variance.py index 5dc182d..e4e5ac1 100644 --- a/pandas_ta/statistics/variance.py +++ b/pandas_ta/statistics/variance.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, verify_series + def variance(close, length=None, ddof=1, offset=None, **kwargs): """Indicator: Variance""" # Validate Arguments @@ -8,7 +9,8 @@ def variance(close, length=None, ddof=1, offset=None, **kwargs): length = int(length) if length and length > 1 else 30 ddof = int(ddof) if ddof >= 0 and ddof < length else 1 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) offset = get_offset(offset) # Calculate Result @@ -25,9 +27,7 @@ def variance(close, length=None, ddof=1, offset=None, **kwargs): return variance - -variance.__doc__ = \ -"""Rolling Variance +variance.__doc__ = """Rolling Variance Sources: @@ -39,9 +39,9 @@ Calculation: Args: close (pd.Series): Series of 'close's length (int): It's period. Default: 30 - ddof (int): Delta Degrees of Freedom. - The divisor used in calculations is N - ddof, - where N represents the number of elements. Default: 1 + ddof (int): Delta Degrees of Freedom. + The divisor used in calculations is N - ddof, + where N represents the number of elements. Default: 1 offset (int): How many periods to offset the result. Default: 0 Kwargs: diff --git a/pandas_ta/statistics/zscore.py b/pandas_ta/statistics/zscore.py index 09165ed..58b15c6 100644 --- a/pandas_ta/statistics/zscore.py +++ b/pandas_ta/statistics/zscore.py @@ -3,6 +3,7 @@ from ..overlap.sma import sma from .stdev import stdev from ..utils import get_offset, verify_series + def zscore(close, length=None, std=None, offset=None, **kwargs): """Indicator: Z Score""" # Validate Arguments @@ -27,9 +28,7 @@ def zscore(close, length=None, std=None, offset=None, **kwargs): return zscore - -zscore.__doc__ = \ -"""Rolling Z Score +zscore.__doc__ = """Rolling Z Score Sources: @@ -54,4 +53,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/trend/adx.py b/pandas_ta/trend/adx.py index e01f7d0..f37aca5 100644 --- a/pandas_ta/trend/adx.py +++ b/pandas_ta/trend/adx.py @@ -4,7 +4,15 @@ from pandas_ta.overlap import rma from pandas_ta.volatility import atr from pandas_ta.utils import get_drift, get_offset, verify_series, zero -def adx(high, low, close, length=None, scalar=None, drift=None, offset=None, **kwargs): + +def adx(high, + low, + close, + length=None, + scalar=None, + drift=None, + offset=None, + **kwargs): """Indicator: ADX""" # Validate Arguments high = verify_series(high) @@ -18,8 +26,8 @@ def adx(high, low, close, length=None, scalar=None, drift=None, offset=None, **k # Calculate Result atr_ = atr(high=high, low=low, close=close, length=length) - up = high - high.shift(drift) # high.diff(drift) - dn = low.shift(drift) - low # low.diff(-drift).shift(drift) + up = high - high.shift(drift) # high.diff(drift) + dn = low.shift(drift) - low # low.diff(-drift).shift(drift) pos = ((up > dn) & (up > 0)) * up neg = ((dn > up) & (dn > 0)) * dn @@ -55,20 +63,18 @@ def adx(high, low, close, length=None, scalar=None, drift=None, offset=None, **k dmp.name = f"DMP_{length}" dmn.name = f"DMN_{length}" - adx.category = dmp.category = dmn.category = 'trend' + adx.category = dmp.category = dmn.category = "trend" # Prepare DataFrame to return data = {adx.name: adx, dmp.name: dmp, dmn.name: dmn} adxdf = DataFrame(data) adxdf.name = f"ADX_{length}" - adxdf.category = 'trend' + adxdf.category = "trend" return adxdf - -adx.__doc__ = \ -"""Average Directional Movement (ADX) +adx.__doc__ = """Average Directional Movement (ADX) Average Directional Movement is meant to quantify trend strength by measuring the amount of movement in a single direction. @@ -142,4 +148,4 @@ Kwargs: Returns: pd.DataFrame: adx, dmp, dmn columns. -""" \ No newline at end of file +""" diff --git a/pandas_ta/trend/amat.py b/pandas_ta/trend/amat.py index d31ebc2..de7586d 100644 --- a/pandas_ta/trend/amat.py +++ b/pandas_ta/trend/amat.py @@ -5,7 +5,14 @@ from .short_run import short_run from pandas_ta.overlap import ema, hma, linreg, rma, sma, wma from pandas_ta.utils import get_offset, verify_series -def amat(close=None, fast=None, slow=None, mamode=None, lookback=None, offset=None, **kwargs): + +def amat(close=None, + fast=None, + slow=None, + mamode=None, + lookback=None, + offset=None, + **kwargs): """Indicator: Archer Moving Averages Trends (AMAT)""" # Validate Arguments close = verify_series(close) @@ -31,11 +38,10 @@ def amat(close=None, fast=None, slow=None, mamode=None, lookback=None, offset=No elif mamode == "wma": fast_ma = wma(close=close, length=fast, **kwargs) slow_ma = wma(close=close, length=slow, **kwargs) - else: # "ema" + else: # "ema" fast_ma = ema(close=close, length=fast, **kwargs) slow_ma = ema(close=close, length=slow, **kwargs) - mas_long = long_run(fast_ma, slow_ma, length=lookback) mas_short = short_run(fast_ma, slow_ma, length=lookback) @@ -63,4 +69,4 @@ def amat(close=None, fast=None, slow=None, mamode=None, lookback=None, offset=No amatdf.name = f"AMAT_{mamode.upper()}_{fast}_{slow}_{lookback}" amatdf.category = "trend" - return amatdf \ No newline at end of file + return amatdf diff --git a/pandas_ta/trend/aroon.py b/pandas_ta/trend/aroon.py index 502edd7..0741e27 100644 --- a/pandas_ta/trend/aroon.py +++ b/pandas_ta/trend/aroon.py @@ -1,6 +1,12 @@ # -*- coding: utf-8 -*- from pandas import DataFrame -from pandas_ta.utils import get_offset, recent_maximum_index, recent_minimum_index, verify_series +from pandas_ta.utils import ( + get_offset, + recent_maximum_index, + recent_minimum_index, + verify_series, +) + def aroon(high, low, length=None, scalar=None, offset=None, **kwargs): """Indicator: Aroon & Aroon Oscillator""" @@ -12,12 +18,14 @@ def aroon(high, low, length=None, scalar=None, offset=None, **kwargs): offset = get_offset(offset) # Calculate Result - periods_from_hh = high.rolling(length + 1).apply(recent_maximum_index, raw=True) - periods_from_ll = low.rolling(length + 1).apply(recent_minimum_index, raw=True) + periods_from_hh = high.rolling(length + 1).apply(recent_maximum_index, + raw=True) + periods_from_ll = low.rolling(length + 1).apply(recent_minimum_index, + raw=True) aroon_up = aroon_down = scalar - aroon_up *= (1 - (periods_from_hh / length)) - aroon_down *= (1 - (periods_from_ll / length)) + aroon_up *= 1 - (periods_from_hh / length) + aroon_down *= 1 - (periods_from_ll / length) aroon_osc = aroon_up - aroon_down # Handle fills @@ -47,7 +55,7 @@ def aroon(high, low, length=None, scalar=None, offset=None, **kwargs): data = { aroon_down.name: aroon_down, aroon_up.name: aroon_up, - aroon_osc.name: aroon_osc + aroon_osc.name: aroon_osc, } aroondf = DataFrame(data) aroondf.name = f"AROON_{length}" @@ -56,9 +64,7 @@ def aroon(high, low, length=None, scalar=None, offset=None, **kwargs): return aroondf - -aroon.__doc__ = \ -"""Aroon & Aroon Oscillator (AROON) +aroon.__doc__ = """Aroon & Aroon Oscillator (AROON) Aroon attempts to identify if a security is trending and how strong. diff --git a/pandas_ta/trend/chop.py b/pandas_ta/trend/chop.py index 4a49e63..1462954 100644 --- a/pandas_ta/trend/chop.py +++ b/pandas_ta/trend/chop.py @@ -4,14 +4,26 @@ from pandas import DataFrame from pandas_ta.volatility import atr from pandas_ta.utils import get_offset, get_drift, verify_series -def chop(high, low, close, length=None, atr_length=None, scalar=None, drift=None, offset=None, **kwargs): + +def chop( + high, + low, + close, + length=None, + atr_length=None, + scalar=None, + drift=None, + offset=None, + **kwargs, +): """Indicator: Choppiness Index (CHOP)""" # Validate Arguments high = verify_series(high) low = verify_series(low) close = verify_series(close) length = int(length) if length and length > 0 else 14 - atr_length = int(atr_length) if atr_length is not None and atr_length > 0 else 1 + atr_length = int( + atr_length) if atr_length is not None and atr_length > 0 else 1 scalar = float(scalar) if scalar else 100 drift = get_drift(drift) offset = get_offset(offset) @@ -42,9 +54,7 @@ def chop(high, low, close, length=None, atr_length=None, scalar=None, drift=None return chop - -chop.__doc__ = \ -"""Choppiness Index (CHOP) +chop.__doc__ = """Choppiness Index (CHOP) The Choppiness Index was created by Australian commodity trader E.W. Dreiss and is designed to determine if the market is choppy @@ -82,4 +92,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/trend/cksp.py b/pandas_ta/trend/cksp.py index f32e7fe..f2a112c 100644 --- a/pandas_ta/trend/cksp.py +++ b/pandas_ta/trend/cksp.py @@ -3,6 +3,7 @@ from pandas import DataFrame from pandas_ta.volatility import atr from pandas_ta.utils import get_offset, verify_series + def cksp(high, low, close, p=None, x=None, q=None, offset=None, **kwargs): """Indicator: Chande Kroll Stop (CKSP)""" # Validate Arguments @@ -50,9 +51,7 @@ def cksp(high, low, close, p=None, x=None, q=None, offset=None, **kwargs): return ckspdf - -cksp.__doc__ = \ -"""Chande Kroll Stop (CKSP) +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, @@ -86,4 +85,4 @@ Kwargs: Returns: pd.DataFrame: long and short columns. -""" \ No newline at end of file +""" diff --git a/pandas_ta/trend/decay.py b/pandas_ta/trend/decay.py index b5ff6d0..d16ec44 100644 --- a/pandas_ta/trend/decay.py +++ b/pandas_ta/trend/decay.py @@ -3,6 +3,7 @@ from math import exp from pandas import DataFrame from pandas_ta.utils import get_offset, verify_series + def decay(close, kind=None, length=None, mode=None, offset=None, **kwargs): """Indicator: Decay""" # Validate Arguments @@ -16,7 +17,7 @@ def decay(close, kind=None, length=None, mode=None, offset=None, **kwargs): if mode == "exp" or kind == "exponential": _mode = "EXP" diff = close.shift(1) - exp(-length) - else: # "linear" + else: # "linear" diff = close.shift(1) - (1 / length) diff[0] = close[0] tdf = DataFrame({"close": close, "diff": diff, "0": 0}) @@ -32,16 +33,14 @@ def decay(close, kind=None, length=None, mode=None, offset=None, **kwargs): if "fill_method" in kwargs: ld.fillna(method=kwargs["fill_method"], inplace=True) - # Name and Categorize it + # Name and Categorize it ld.name = f"{_mode}DECAY_{length}" ld.category = "trend" return ld - -decay.__doc__ = \ -"""Decay +decay.__doc__ = """Decay Creates a decay moving forward from prior signals like crosses. The default is "linear". Exponential is optional as "exponential" or "exp". @@ -70,4 +69,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/trend/decreasing.py b/pandas_ta/trend/decreasing.py index f8cda99..d0c7cb9 100644 --- a/pandas_ta/trend/decreasing.py +++ b/pandas_ta/trend/decreasing.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from pandas_ta.utils import get_offset, verify_series + def decreasing(close, length=None, asint=True, offset=None, **kwargs): """Indicator: Decreasing""" # Validate Arguments @@ -30,9 +31,7 @@ def decreasing(close, length=None, asint=True, offset=None, **kwargs): return decreasing - -decreasing.__doc__ = \ -"""Decreasing +decreasing.__doc__ = """Decreasing Returns True or False if the series is decreasing over a periods. By default, it returns True and False as 1 and 0 respectively with kwarg 'asint'. @@ -56,4 +55,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/trend/dpo.py b/pandas_ta/trend/dpo.py index 8040fb2..4cd4c1a 100644 --- a/pandas_ta/trend/dpo.py +++ b/pandas_ta/trend/dpo.py @@ -2,6 +2,7 @@ from pandas_ta.overlap import sma from pandas_ta.utils import get_offset, verify_series + def dpo(close, length=None, centered=True, offset=None, **kwargs): """Indicator: Detrend Price Oscillator (DPO)""" # Validate Arguments @@ -12,7 +13,7 @@ def dpo(close, length=None, centered=True, offset=None, **kwargs): # Calculate Result t = int(0.5 * length) + 1 ma = sma(close, length) - + dpo = close - ma.shift(t) if centered: dpo = (close.shift(t) - ma).shift(-t) @@ -34,9 +35,7 @@ def dpo(close, length=None, centered=True, offset=None, **kwargs): return dpo - -dpo.__doc__ = \ -"""Detrend Price Oscillator (DPO) +dpo.__doc__ = """Detrend Price Oscillator (DPO) Is an indicator designed to remove trend from price and make it easier to identify cycles. @@ -51,7 +50,7 @@ Calculation: length=20, centered=True SMA = Simple Moving Average t = int(0.5 * length) + 1 - + DPO = close.shift(t) - SMA(close, length) if centered: DPO = DPO.shift(-t) @@ -68,4 +67,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/trend/increasing.py b/pandas_ta/trend/increasing.py index b696e80..960ade4 100644 --- a/pandas_ta/trend/increasing.py +++ b/pandas_ta/trend/increasing.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from pandas_ta.utils import get_offset, verify_series + def increasing(close, length=None, asint=True, offset=None, **kwargs): """Indicator: Increasing""" # Validate Arguments @@ -30,9 +31,7 @@ def increasing(close, length=None, asint=True, offset=None, **kwargs): return increasing - -increasing.__doc__ = \ -"""Increasing +increasing.__doc__ = """Increasing Returns True or False if the series is increasing over a periods. By default, it returns True and False as 1 and 0 respectively with kwarg 'asint'. @@ -56,4 +55,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/trend/long_run.py b/pandas_ta/trend/long_run.py index 8b7b771..b28e859 100644 --- a/pandas_ta/trend/long_run.py +++ b/pandas_ta/trend/long_run.py @@ -3,6 +3,7 @@ from .decreasing import decreasing from .increasing import increasing from pandas_ta.utils import get_offset, verify_series + def long_run(fast, slow, length=None, offset=None, **kwargs): """Indicator: Long Run""" # Validate Arguments @@ -12,8 +13,10 @@ def long_run(fast, slow, length=None, offset=None, **kwargs): offset = get_offset(offset) # Calculate Result - pb = increasing(fast, length) & decreasing(slow, length) # potential bottom or bottom - bi = increasing(fast, length) & increasing(slow, length) # fast and slow are increasing + pb = increasing(fast, length) & decreasing( + slow, length) # potential bottom or bottom + bi = increasing(fast, length) & increasing( + slow, length) # fast and slow are increasing long_run = pb | bi # Offset @@ -30,4 +33,4 @@ def long_run(fast, slow, length=None, offset=None, **kwargs): long_run.name = f"LR_{length}" long_run.category = "trend" - return long_run \ No newline at end of file + return long_run diff --git a/pandas_ta/trend/psar.py b/pandas_ta/trend/psar.py index d112b04..ea5effb 100644 --- a/pandas_ta/trend/psar.py +++ b/pandas_ta/trend/psar.py @@ -3,6 +3,7 @@ from numpy import NaN as npNaN from pandas import DataFrame, Series from pandas_ta.utils import get_offset, verify_series + def psar(high, low, close=None, af=None, max_af=None, offset=None, **kwargs): """Indicator: Parabolic Stop and Reverse (PSAR)""" # Validate Arguments @@ -101,7 +102,7 @@ def psar(high, low, close=None, af=None, max_af=None, offset=None, **kwargs): f"PSARl{_params}": long, f"PSARs{_params}": short, f"PSARaf{_params}": _af, - f"PSARr{_params}": reversal + f"PSARr{_params}": reversal, } psardf = DataFrame(data) psardf.name = f"PSAR{_params}" @@ -110,9 +111,7 @@ def psar(high, low, close=None, af=None, max_af=None, offset=None, **kwargs): return psardf - -psar.__doc__ = \ -"""Parabolic Stop and Reverse (psar) +psar.__doc__ = """Parabolic Stop and Reverse (psar) Parabolic Stop and Reverse @@ -138,4 +137,4 @@ Kwargs: Returns: pd.DataFrame: long, short, af, and reversal columns. -""" \ No newline at end of file +""" diff --git a/pandas_ta/trend/qstick.py b/pandas_ta/trend/qstick.py index 957a771..4619d17 100644 --- a/pandas_ta/trend/qstick.py +++ b/pandas_ta/trend/qstick.py @@ -2,6 +2,7 @@ from pandas_ta.overlap import dema, ema, hma, rma, sma from pandas_ta.utils import get_offset, non_zero_range, verify_series + def qstick(open_, close, length=None, offset=None, **kwargs): """Indicator: Q Stick""" # Validate Arguments @@ -14,11 +15,16 @@ def qstick(open_, close, length=None, offset=None, **kwargs): # Calculate Result diff = non_zero_range(close, open_) - if ma in [None, "sma"]: qstick = sma(diff, length=length) - if ma == "dema": qstick = dema(diff, length=length, **kwargs) - if ma == "ema": qstick = ema(diff, length=length, **kwargs) - if ma == "hma": qstick = hma(diff, length=length) - if ma == "rma": qstick = rma(diff, length=length) + if ma in [None, "sma"]: + qstick = sma(diff, length=length) + if ma == "dema": + qstick = dema(diff, length=length, **kwargs) + if ma == "ema": + qstick = ema(diff, length=length, **kwargs) + if ma == "hma": + qstick = hma(diff, length=length) + if ma == "rma": + qstick = rma(diff, length=length) # Offset if offset != 0: @@ -37,9 +43,7 @@ def qstick(open_, close, length=None, offset=None, **kwargs): return qstick - -qstick.__doc__ = \ -"""Q Stick +qstick.__doc__ = """Q Stick The Q Stick indicator, developed by Tushar Chande, attempts to quantify and identify trends in candlestick charts. @@ -66,4 +70,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/trend/short_run.py b/pandas_ta/trend/short_run.py index 23762f8..1612f46 100644 --- a/pandas_ta/trend/short_run.py +++ b/pandas_ta/trend/short_run.py @@ -3,6 +3,7 @@ from .decreasing import decreasing from .increasing import increasing from pandas_ta.utils import get_offset, verify_series + def short_run(fast, slow, length=None, offset=None, **kwargs): """Indicator: Short Run""" # Validate Arguments @@ -12,8 +13,10 @@ def short_run(fast, slow, length=None, offset=None, **kwargs): offset = get_offset(offset) # Calculate Result - pt = decreasing(fast, length) & increasing(slow, length) # potential top or top - bd = decreasing(fast, length) & decreasing(slow, length) # fast and slow are decreasing + pt = decreasing(fast, length) & increasing(slow, + length) # potential top or top + bd = decreasing(fast, length) & decreasing( + slow, length) # fast and slow are decreasing short_run = pt | bd # Offset @@ -30,4 +33,4 @@ def short_run(fast, slow, length=None, offset=None, **kwargs): short_run.name = f"SR_{length}" short_run.category = "trend" - return short_run \ No newline at end of file + return short_run diff --git a/pandas_ta/trend/ttm_trend.py b/pandas_ta/trend/ttm_trend.py index ab02256..fead880 100644 --- a/pandas_ta/trend/ttm_trend.py +++ b/pandas_ta/trend/ttm_trend.py @@ -3,6 +3,7 @@ from pandas import DataFrame from pandas_ta.overlap import hl2 from pandas_ta.utils import get_offset, verify_series + def ttm_trend(high, low, close, length=None, offset=None, **kwargs): """Indicator: TTM Trend (TTM_TRND)""" # Validate arguments @@ -45,9 +46,7 @@ def ttm_trend(high, low, close, length=None, offset=None, **kwargs): return df - -ttm_trend.__doc__ = \ -"""TTM Trend (TTM_TRND) +ttm_trend.__doc__ = """TTM Trend (TTM_TRND) This indicator is from John Carters book “Mastering the Trade” and plots the bars green or red. It checks if the price is above or under the average price of diff --git a/pandas_ta/trend/vortex.py b/pandas_ta/trend/vortex.py index 221c38a..1580b18 100644 --- a/pandas_ta/trend/vortex.py +++ b/pandas_ta/trend/vortex.py @@ -3,6 +3,7 @@ from pandas import DataFrame from pandas_ta.volatility import true_range from pandas_ta.utils import get_drift, get_offset, verify_series, zero + def vortex(high, low, close, length=None, drift=None, offset=None, **kwargs): """Indicator: Vortex""" # Validate arguments @@ -10,7 +11,8 @@ def vortex(high, low, close, length=None, drift=None, offset=None, **kwargs): low = verify_series(low) close = verify_series(close) length = length if length and length > 0 else 14 - min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) drift = get_drift(drift) offset = get_offset(offset) @@ -51,9 +53,7 @@ def vortex(high, low, close, length=None, drift=None, offset=None, **kwargs): return vtxdf - -vortex.__doc__ = \ -"""Vortex +vortex.__doc__ = """Vortex Two oscillators that capture positive and negative trend movement. @@ -88,4 +88,4 @@ Kwargs: Returns: pd.DataFrame: vip and vim columns -""" \ No newline at end of file +""" diff --git a/pandas_ta/utils/__init__.py b/pandas_ta/utils/__init__.py index f0b1f6a..8a9bbdb 100644 --- a/pandas_ta/utils/__init__.py +++ b/pandas_ta/utils/__init__.py @@ -3,4 +3,4 @@ from ._candles import * from ._core import * from ._math import * from ._signals import * -from ._time import * \ No newline at end of file +from ._time import * diff --git a/pandas_ta/utils/_candles.py b/pandas_ta/utils/_candles.py index 9c8ba89..a40b853 100644 --- a/pandas_ta/utils/_candles.py +++ b/pandas_ta/utils/_candles.py @@ -4,16 +4,16 @@ from pandas import Series from ._core import non_zero_range - def candle_color(open_: Series, close: Series) -> Series: color = close.copy().astype(int) color[close >= open_] = 1 color[close < open_] = -1 return color + def high_low_range(high: Series, low: Series) -> Series: return non_zero_range(high, low) def real_body(close: Series, open_: Series) -> Series: - return non_zero_range(close, open_) \ No newline at end of file + return non_zero_range(close, open_) diff --git a/pandas_ta/utils/_core.py b/pandas_ta/utils/_core.py index 29b1e59..0e6a6ae 100644 --- a/pandas_ta/utils/_core.py +++ b/pandas_ta/utils/_core.py @@ -8,10 +8,13 @@ from pandas import DataFrame, Series from pandas.api.types import is_datetime64_any_dtype - def category_files(category: str) -> list: """Helper function to return all filenames in the category directory.""" - files = [x.stem for x in list(Path(f"pandas_ta/{category}/").glob("*.py")) if x.stem != "__init__"] + files = [ + x.stem + for x in list(Path(f"pandas_ta/{category}/").glob("*.py")) + if x.stem != "__init__" + ] return files @@ -30,7 +33,8 @@ def is_datetime_ordered(df: DataFrame or Series) -> bool: index_is_datetime = is_datetime64_any_dtype(df.index) try: ordered = df.index[0] < df.index[-1] - except RuntimeWarning: pass + except RuntimeWarning: + pass finally: return True if index_is_datetime and ordered else False @@ -42,8 +46,7 @@ def is_percent(x: int or float) -> bool: def non_zero_range(high: Series, low: Series) -> Series: - """Returns the difference of two series and adds epsilon to any zero values. This occurs commonly in crypto data when 'high' = 'low'. - """ + """Returns the difference of two series and adds epsilon to any zero values. This occurs commonly in crypto data when 'high' = 'low'.""" diff = high - low if diff.eq(0).any().any(): diff += sflt.epsilon @@ -60,7 +63,7 @@ def recent_minimum_index(x): def signed_series(series: Series, initial: int = None) -> Series: """Returns a Signed Series with or without an initial value - + Default Example: series = Series([3, 2, 2, 1, 1, 5, 6, 6, 7, 5]) and returns: @@ -74,7 +77,9 @@ def signed_series(series: Series, initial: int = None) -> Series: return sign -def unsigned_differences(series: Series, amount: int = None, **kwargs) -> Series: +def unsigned_differences(series: Series, + amount: int = None, + **kwargs) -> Series: """Unsigned Differences Returns two Series, an unsigned positive and unsigned negative series based on the differences of the original series. The positive series are only the diff --git a/pandas_ta/utils/_math.py b/pandas_ta/utils/_math.py index 6ecc812..4682205 100644 --- a/pandas_ta/utils/_math.py +++ b/pandas_ta/utils/_math.py @@ -20,7 +20,6 @@ from pandas_ta import Imports from ._core import verify_series - def combination(**kwargs): """https://stackoverflow.com/questions/4941753/is-there-a-math-ncr-function-in-python""" n = int(fabs(kwargs.pop("n", 1))) @@ -34,7 +33,7 @@ def combination(**kwargs): if r == 0: return 1 - numerator = reduce(mul, range(n, n - r, -1), 1) + numerator = reduce(mul, range(n, n - r, -1), 1) denominator = reduce(mul, range(1, r + 1), 1) return numerator // denominator @@ -73,7 +72,9 @@ def linear_regression(x: Series, y: Series) -> dict: m, n = x.size, y.size if m != n: - print(f"[X] Linear Regression X and y observations do not match: {m} != {n}") + print( + f"[X] Linear Regression X and y observations do not match: {m} != {n}" + ) return if Imports["sklearn"]: @@ -124,7 +125,7 @@ def symmetric_triangle(n: int = None, **kwargs) -> list: if n > 2: if n % 2 == 0: - front = [i + 1 for i in range(0, floor(n/2))] + front = [i + 1 for i in range(0, floor(n / 2))] triangle = front + front[::-1] else: front = [i + 1 for i in range(0, floor(0.5 * (n + 1)))] @@ -141,8 +142,10 @@ def symmetric_triangle(n: int = None, **kwargs) -> list: def weights(w): + def _dot(x): return dot(w, x) + return _dot @@ -154,6 +157,7 @@ def zero(x: [int, float]) -> [int, float]: # TESTING + def df_error_analysis(dfA: DataFrame, dfB: DataFrame, **kwargs) -> DataFrame: """DataFrame Correlation Analysis helper""" corr_method = kwargs.pop("corr_method", "pearson") @@ -176,6 +180,7 @@ def df_error_analysis(dfA: DataFrame, dfB: DataFrame, **kwargs) -> DataFrame: # PRIVATE + def _linear_regression_np(x: Series, y: Series) -> dict: """Simple Linear Regression in Numpy for two 1d arrays for environments without the sklearn package.""" @@ -184,7 +189,7 @@ def _linear_regression_np(x: Series, y: Series) -> dict: y_sum = y.sum() # 1st row, 2nd col value corr(x, y) - r = npCorrcoef(x, y)[0,1] + r = npCorrcoef(x, y)[0, 1] r_mixture = m * (x * y).sum() - x_sum * y_sum b = r_mixture / (m * (x * x).sum() - x_sum * x_sum) @@ -193,11 +198,14 @@ def _linear_regression_np(x: Series, y: Series) -> dict: # seterr(divide="ignore", invalid="ignore") return { - "a": a, "b": b, "r": r, + "a": a, + "b": b, + "r": r, "t": r / npSqrt((1 - r * r) / (m - 2)), - "line": line + "line": line, } + def _linear_regression_sklearn(x, y): """Simple Linear Regression in Scikit Learn for two 1d arrays for environments with the sklearn package.""" @@ -209,7 +217,9 @@ def _linear_regression_sklearn(x, y): a, b = regression.intercept_, regression.coef_[0] return { - "a": a, "b": b, "r": r, + "a": a, + "b": b, + "r": r, "t": r / npSqrt((1 - r * r) / (x.size - 2)), - "line": a + b * x - } \ No newline at end of file + "line": a + b * x, + } diff --git a/pandas_ta/utils/_signals.py b/pandas_ta/utils/_signals.py index df99d71..4ee9138 100644 --- a/pandas_ta/utils/_signals.py +++ b/pandas_ta/utils/_signals.py @@ -5,15 +5,14 @@ from ._core import get_offset, verify_series from ._math import zero - def _above_below( - series_a: Series, - series_b: Series, - above: bool = True, - asint: bool = True, - offset: int = None, - **kwargs - ): + series_a: Series, + series_b: Series, + above: bool = True, + asint: bool = True, + offset: int = None, + **kwargs, +): series_a = verify_series(series_a) series_b = verify_series(series_b) offset = get_offset(offset) @@ -41,74 +40,92 @@ def _above_below( return current -def above( - series_a: Series, - series_b: Series, - asint: bool = True, - offset: int = None, - **kwargs - ): - return _above_below(series_a, series_b, above=True, asint=asint, offset=offset, **kwargs) +def above(series_a: Series, + series_b: Series, + asint: bool = True, + offset: int = None, + **kwargs): + return _above_below(series_a, + series_b, + above=True, + asint=asint, + offset=offset, + **kwargs) -def above_value( - series_a: Series, - value: float, - asint: bool = True, - offset: int = None, - **kwargs - ): +def above_value(series_a: Series, + value: float, + asint: bool = True, + offset: int = None, + **kwargs): if not isinstance(value, (int, float, complex)): print("[X] value is not a number") return - series_b = Series(value, index=series_a.index, name=f"{value}".replace(".","_")) - return _above_below(series_a, series_b, above=True, asint=asint, offset=offset, **kwargs) + series_b = Series(value, + index=series_a.index, + name=f"{value}".replace(".", "_")) + return _above_below(series_a, + series_b, + above=True, + asint=asint, + offset=offset, + **kwargs) -def below( - series_a: Series, - series_b: Series, - asint: bool =True, - offset: int =None - ,**kwargs - ): - return _above_below(series_a, series_b, above=False, asint=asint, offset=offset, **kwargs) +def below(series_a: Series, + series_b: Series, + asint: bool = True, + offset: int = None, + **kwargs): + return _above_below(series_a, + series_b, + above=False, + asint=asint, + offset=offset, + **kwargs) -def below_value( - series_a: Series, - value: float, - asint: bool = True, - offset: int = None, - **kwargs - ): +def below_value(series_a: Series, + value: float, + asint: bool = True, + offset: int = None, + **kwargs): if not isinstance(value, (int, float, complex)): print("[X] value is not a number") return - series_b = Series(value, index=series_a.index, name=f"{value}".replace(".","_")) - return _above_below(series_a, series_b, above=False, asint=asint, offset=offset, **kwargs) + series_b = Series(value, + index=series_a.index, + name=f"{value}".replace(".", "_")) + return _above_below(series_a, + series_b, + above=False, + asint=asint, + offset=offset, + **kwargs) def cross_value( - series_a: Series, - value: float, - above: bool = True, - asint: bool = True, - offset: int = None, - **kwargs - ): - series_b = Series(value, index=series_a.index, name=f"{value}".replace(".","_")) + series_a: Series, + value: float, + above: bool = True, + asint: bool = True, + offset: int = None, + **kwargs, +): + series_b = Series(value, + index=series_a.index, + name=f"{value}".replace(".", "_")) return cross(series_a, series_b, above, asint, offset, **kwargs) def cross( - series_a: Series, - series_b: Series, - above: bool = True, - asint: bool = True, - offset: int = None, - **kwargs - ): + series_a: Series, + series_b: Series, + above: bool = True, + asint: bool = True, + offset: int = None, + **kwargs, +): series_a = verify_series(series_a) series_b = verify_series(series_b) offset = get_offset(offset) @@ -117,8 +134,8 @@ def cross( series_b.apply(zero) # Calculate Result - current = series_a > series_b # current is above - previous = series_a.shift(1) < series_b.shift(1) # previous is below + current = series_a > series_b # current is above + previous = series_a.shift(1) < series_b.shift(1) # previous is below # above if both are true, below if both are false cross = current & previous if above else ~current & ~previous @@ -136,13 +153,19 @@ def cross( return cross - -def signals(indicator, xa, xb, cross_values, xserie, xserie_a, xserie_b, cross_series, offset) -> DataFrame: +def signals(indicator, xa, xb, cross_values, xserie, xserie_a, xserie_b, + cross_series, offset) -> DataFrame: df = DataFrame() if xa is not None and isinstance(xa, (int, float)): if cross_values: - crossed_above_start = cross_value(indicator, xa, above=True, offset=offset) - crossed_above_end = cross_value(indicator, xa, above=False, offset=offset) + crossed_above_start = cross_value(indicator, + xa, + above=True, + offset=offset) + crossed_above_end = cross_value(indicator, + xa, + above=False, + offset=offset) df[crossed_above_start.name] = crossed_above_start df[crossed_above_end.name] = crossed_above_end else: @@ -151,8 +174,14 @@ def signals(indicator, xa, xb, cross_values, xserie, xserie_a, xserie_b, cross_s if xb is not None and isinstance(xb, (int, float)): if cross_values: - crossed_below_start = cross_value(indicator, xb, above=True, offset=offset) - crossed_below_end = cross_value(indicator, xb, above=False, offset=offset) + crossed_below_start = cross_value(indicator, + xb, + above=True, + offset=offset) + crossed_below_end = cross_value(indicator, + xb, + above=False, + offset=offset) df[crossed_below_start.name] = crossed_below_start df[crossed_below_end.name] = crossed_below_end else: @@ -167,7 +196,10 @@ def signals(indicator, xa, xb, cross_values, xserie, xserie_a, xserie_b, cross_s if xserie_a is not None and verify_series(xserie_a): if cross_series: - cross_serie_above = cross(indicator, xserie_a, above=True, offset=offset) + cross_serie_above = cross(indicator, + xserie_a, + above=True, + offset=offset) else: cross_serie_above = above(indicator, xserie_a, offset=offset) @@ -175,10 +207,13 @@ def signals(indicator, xa, xb, cross_values, xserie, xserie_a, xserie_b, cross_s if xserie_b is not None and verify_series(xserie_b): if cross_series: - cross_serie_below = cross(indicator, xserie_b, above=False, offset=offset) + cross_serie_below = cross(indicator, + xserie_b, + above=False, + offset=offset) else: cross_serie_below = below(indicator, xserie_b, offset=offset) df[cross_serie_below.name] = cross_serie_below - return df \ No newline at end of file + return df diff --git a/pandas_ta/utils/_time.py b/pandas_ta/utils/_time.py index 24f7b03..f20e4ec 100644 --- a/pandas_ta/utils/_time.py +++ b/pandas_ta/utils/_time.py @@ -5,21 +5,20 @@ from time import perf_counter from pandas_ta import EXCHANGE_TZ - def final_time(stime): time_diff = perf_counter() - stime return f"{time_diff * 1000:2.4f} ms ({time_diff:2.4f} s)" -def get_time(exchange: str = "NYSE", to_string:bool = False) -> (None, str): - tz = EXCHANGE_TZ["NYSE"] # Default is NYSE (Eastern Time Zone) +def get_time(exchange: str = "NYSE", to_string: bool = False) -> (None, str): + tz = EXCHANGE_TZ["NYSE"] # Default is NYSE (Eastern Time Zone) if isinstance(exchange, str): exchange = exchange.upper() tz = EXCHANGE_TZ[exchange] day_of_year = datetime.utcnow().timetuple().tm_yday today = datetime.utcnow() - s = f"Today: {today}, " + s = f"Today: {today}, " s += f"Day {day_of_year}/365 ({100 * round(day_of_year/365, 2)}%), " s += f"{exchange} Time: {(today.timetuple().tm_hour + tz) % 12}:{today.timetuple().tm_min}:{today.timetuple().tm_sec}" return s if to_string else print(s) diff --git a/pandas_ta/volatility/__init__.py b/pandas_ta/volatility/__init__.py index fa2abda..c280821 100644 --- a/pandas_ta/volatility/__init__.py +++ b/pandas_ta/volatility/__init__.py @@ -10,4 +10,4 @@ from .pdist import pdist from .natr import natr from .rvi import rvi from .true_range import true_range -from .ui import ui \ No newline at end of file +from .ui import ui diff --git a/pandas_ta/volatility/aberration.py b/pandas_ta/volatility/aberration.py index 717abe8..faf670a 100644 --- a/pandas_ta/volatility/aberration.py +++ b/pandas_ta/volatility/aberration.py @@ -6,7 +6,14 @@ from ..overlap.hlc3 import hlc3 from ..overlap.sma import sma from ..utils import get_offset, non_zero_range, verify_series -def aberration(high, low, close, length=None, atr_length=None, offset=None, **kwargs): + +def aberration(high, + low, + close, + length=None, + atr_length=None, + offset=None, + **kwargs): """Indicator: Aberration (ABER)""" # Validate arguments high = verify_series(high) @@ -53,12 +60,7 @@ def aberration(high, low, close, length=None, atr_length=None, offset=None, **kw xg.category = atr_.category = zg.category # Prepare DataFrame to return - data = { - zg.name: zg, - sg.name: sg, - xg.name: xg, - atr_.name: atr_ - } + data = {zg.name: zg, sg.name: sg, xg.name: xg, atr_.name: atr_} aberdf = DataFrame(data) aberdf.name = f"ABER{_props}" aberdf.category = zg.category @@ -66,9 +68,7 @@ def aberration(high, low, close, length=None, atr_length=None, offset=None, **kw return aberdf - -aberration.__doc__ = \ -"""Aberration +aberration.__doc__ = """Aberration A volatility indicator similar to Keltner Channels. @@ -102,4 +102,4 @@ Kwargs: Returns: pd.DataFrame: zg, sg, xg, atr columns. -""" \ No newline at end of file +""" diff --git a/pandas_ta/volatility/accbands.py b/pandas_ta/volatility/accbands.py index 565bad7..b6ba1df 100644 --- a/pandas_ta/volatility/accbands.py +++ b/pandas_ta/volatility/accbands.py @@ -3,7 +3,18 @@ from pandas import DataFrame from pandas_ta.overlap import ema, sma from pandas_ta.utils import get_drift, get_offset, non_zero_range, verify_series -def accbands(high, low, close, length=None, c=None, drift=None, mamode=None, offset=None, **kwargs): + +def accbands( + high, + low, + close, + length=None, + c=None, + drift=None, + mamode=None, + offset=None, + **kwargs, +): """Indicator: Acceleration Bands (ACCBANDS)""" # Validate arguments high = verify_series(high) @@ -12,13 +23,14 @@ def accbands(high, low, close, length=None, c=None, drift=None, mamode=None, off high_low_range = non_zero_range(high, low) length = int(length) if length and length > 0 else 20 c = float(c) if c and c > 0 else 4 - min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) mamode = mamode.lower() if mamode else "sma" drift = get_drift(drift) offset = get_offset(offset) # Calculate Result - hl_ratio = high_low_range / (high + low) + hl_ratio = high_low_range / (high + low) hl_ratio *= c _lower = low * (1 - hl_ratio) _upper = high * (1 + hl_ratio) @@ -28,11 +40,11 @@ def accbands(high, low, close, length=None, c=None, drift=None, mamode=None, off # mid = close.ewm(span=length, min_periods=min_periods).mean() # upper = _upper.ewm(span=length, min_periods=min_periods).mean() lower = ema(_lower, length=length) - mid = ema(close, length=length) + mid = ema(close, length=length) upper = ema(_upper, length=length) - else: # "sma" + else: # "sma" lower = sma(_lower, length=length) - mid = sma(close, length=length) + mid = sma(close, length=length) upper = sma(_upper, length=length) # Offset @@ -66,9 +78,7 @@ def accbands(high, low, close, length=None, c=None, drift=None, mamode=None, off return accbandsdf - -accbands.__doc__ = \ -"""Acceleration Bands (ACCBANDS) +accbands.__doc__ = """Acceleration Bands (ACCBANDS) Acceleration Bands created by Price Headley plots upper and lower envelope bands around a simple moving average. @@ -110,4 +120,4 @@ Kwargs: Returns: pd.DataFrame: lower, mid, upper columns. -""" \ No newline at end of file +""" diff --git a/pandas_ta/volatility/atr.py b/pandas_ta/volatility/atr.py index 26ff710..1146d9b 100644 --- a/pandas_ta/volatility/atr.py +++ b/pandas_ta/volatility/atr.py @@ -3,7 +3,15 @@ from pandas_ta.overlap import ema, rma from .true_range import true_range from pandas_ta.utils import get_drift, get_offset, verify_series -def atr(high, low, close, length=None, mamode=None, drift=None, offset=None, **kwargs): + +def atr(high, + low, + close, + length=None, + mamode=None, + drift=None, + offset=None, + **kwargs): """Indicator: Average True Range (ATR)""" # Validate arguments high = verify_series(high) @@ -45,9 +53,7 @@ def atr(high, low, close, length=None, mamode=None, drift=None, offset=None, **k return atr - -atr.__doc__ = \ -"""Average True Range (ATR) +atr.__doc__ = """Average True Range (ATR) Averge True Range is used to measure volatility, especially volatility caused by gaps or limit moves. @@ -86,4 +92,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/volatility/bbands.py b/pandas_ta/volatility/bbands.py index e4f3c7b..3aac54b 100644 --- a/pandas_ta/volatility/bbands.py +++ b/pandas_ta/volatility/bbands.py @@ -4,12 +4,13 @@ from pandas_ta.overlap import ema, sma from pandas_ta.statistics import stdev from pandas_ta.utils import get_offset, verify_series + def bbands(close, length=None, std=None, mamode=None, offset=None, **kwargs): """Indicator: Bollinger Bands (BBANDS)""" # Validate arguments close = verify_series(close) length = int(length) if length and length > 0 else 5 - std = float(std) if std and std > 0 else 2. + std = float(std) if std and std > 0 else 2.0 mamode = mamode.lower() if mamode else "sma" offset = get_offset(offset) @@ -56,9 +57,7 @@ def bbands(close, length=None, std=None, mamode=None, offset=None, **kwargs): return bbandsdf - -bbands.__doc__ = \ -"""Bollinger Bands (BBANDS) +bbands.__doc__ = """Bollinger Bands (BBANDS) A popular volatility indicator. @@ -76,7 +75,7 @@ Calculation: MID = EMA(close, length) else: MID = SMA(close, length) - + LOWER = MID - std * stdev UPPER = MID + std * stdev @@ -93,4 +92,4 @@ Kwargs: Returns: pd.DataFrame: lower, mid, upper columns. -""" \ No newline at end of file +""" diff --git a/pandas_ta/volatility/donchian.py b/pandas_ta/volatility/donchian.py index bd17970..8a57a6c 100644 --- a/pandas_ta/volatility/donchian.py +++ b/pandas_ta/volatility/donchian.py @@ -2,15 +2,27 @@ from pandas import DataFrame from ..utils import get_offset, verify_series -def donchian(high, low, lower_length=None, upper_length=None, offset=None, **kwargs): + +def donchian(high, + low, + lower_length=None, + upper_length=None, + offset=None, + **kwargs): """Indicator: Donchian Channels (DC)""" # Validate arguments high = verify_series(high) low = verify_series(low) - lower_length = int(lower_length) if lower_length and lower_length > 0 else 20 - upper_length = int(upper_length) if upper_length and upper_length > 0 else 20 - lower_min_periods = int(kwargs["lower_min_periods"]) if "lower_min_periods" in kwargs and kwargs["lower_min_periods"] is not None else lower_length - upper_min_periods = int(kwargs["upper_min_periods"]) if "upper_min_periods" in kwargs and kwargs["upper_min_periods"] is not None else upper_length + lower_length = int( + lower_length) if lower_length and lower_length > 0 else 20 + upper_length = int( + upper_length) if upper_length and upper_length > 0 else 20 + lower_min_periods = ( + int(kwargs["lower_min_periods"]) if "lower_min_periods" in kwargs and + kwargs["lower_min_periods"] is not None else lower_length) + upper_min_periods = ( + int(kwargs["upper_min_periods"]) if "upper_min_periods" in kwargs and + kwargs["upper_min_periods"] is not None else upper_length) offset = get_offset(offset) # Calculate Result @@ -49,11 +61,9 @@ def donchian(high, low, lower_length=None, upper_length=None, offset=None, **kwa return dcdf +donchian.__doc__ = """Donchian Channels (DC) -donchian.__doc__ = \ -"""Donchian Channels (DC) - -Donchian Channels are used to measure volatility, similar to +Donchian Channels are used to measure volatility, similar to Bollinger Bands and Keltner Channels. Sources: @@ -79,4 +89,4 @@ Kwargs: Returns: pd.DataFrame: lower, mid, upper columns. -""" \ No newline at end of file +""" diff --git a/pandas_ta/volatility/kc.py b/pandas_ta/volatility/kc.py index 9f06a15..21bc0ce 100644 --- a/pandas_ta/volatility/kc.py +++ b/pandas_ta/volatility/kc.py @@ -7,7 +7,14 @@ from pandas_ta.overlap import ema, hlc3, sma from pandas_ta.utils import get_offset, high_low_range, non_zero_range, verify_series -def kc(high, low, close, length=None, scalar=None, mamode=None, offset=None, **kwargs): +def kc(high, + low, + close, + length=None, + scalar=None, + mamode=None, + offset=None, + **kwargs): """Indicator: Keltner Channels (KC)""" # Validate arguments high = verify_series(high) @@ -69,9 +76,7 @@ def kc(high, low, close, length=None, scalar=None, mamode=None, offset=None, **k return kcdf - -kc.__doc__ = \ -"""Keltner Channels (KC) +kc.__doc__ = """Keltner Channels (KC) A popular volatility indicator similar to Bollinger Bands and Donchian Channels. @@ -97,7 +102,7 @@ Calculation: elif mamode == "sma": BASIS = sma(close, length) BAND = sma(RANGE, length) - + LOWER = BASIS - scalar * BAND UPPER = BASIS + scalar * BAND @@ -118,4 +123,4 @@ Kwargs: Returns: pd.DataFrame: lower, basis, upper columns. -""" \ No newline at end of file +""" diff --git a/pandas_ta/volatility/massi.py b/pandas_ta/volatility/massi.py index 7cf7efa..2d4d3ea 100644 --- a/pandas_ta/volatility/massi.py +++ b/pandas_ta/volatility/massi.py @@ -2,6 +2,7 @@ from ..overlap.ema import ema from ..utils import get_offset, non_zero_range, verify_series + def massi(high, low, fast=None, slow=None, offset=None, **kwargs): """Indicator: Mass Index (MASSI)""" # Validate arguments @@ -12,7 +13,8 @@ def massi(high, low, fast=None, slow=None, offset=None, **kwargs): slow = int(slow) if slow and slow > 0 else 25 if slow < fast: fast, slow = slow, fast - min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else fast + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else fast) offset = get_offset(offset) # Calculate Result @@ -39,9 +41,7 @@ def massi(high, low, fast=None, slow=None, offset=None, **kwargs): return massi - -massi.__doc__ = \ -"""Mass Index (MASSI) +massi.__doc__ = """Mass Index (MASSI) The Mass Index is a non-directional volatility indicator that utilitizes the High-Low Range to identify trend reversals based on range expansions. @@ -73,4 +73,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/volatility/natr.py b/pandas_ta/volatility/natr.py index 670d5c8..16db64d 100644 --- a/pandas_ta/volatility/natr.py +++ b/pandas_ta/volatility/natr.py @@ -2,7 +2,18 @@ from .atr import atr from ..utils import get_drift, get_offset, verify_series -def natr(high, low, close, length=None, mamode=None, scalar=None, drift=None, offset=None, **kwargs): + +def natr( + high, + low, + close, + length=None, + mamode=None, + scalar=None, + drift=None, + offset=None, + **kwargs, +): """Indicator: Normalized Average True Range (NATR)""" # Validate arguments high = verify_series(high) @@ -16,7 +27,16 @@ def natr(high, low, close, length=None, mamode=None, scalar=None, drift=None, of # Calculate Result natr = scalar / close - natr *= atr(high=high, low=low, close=close, length=length, mamode=mamode, drift=drift, offset=offset, **kwargs) + natr *= atr( + high=high, + low=low, + close=close, + length=length, + mamode=mamode, + drift=drift, + offset=offset, + **kwargs, + ) # Offset if offset != 0: @@ -35,9 +55,7 @@ def natr(high, low, close, length=None, mamode=None, scalar=None, drift=None, of return natr - -natr.__doc__ = \ -"""Normalized Average True Range (NATR) +natr.__doc__ = """Normalized Average True Range (NATR) Normalized Average True Range attempt to normalize the average true range. @@ -65,4 +83,4 @@ Kwargs: Returns: pd.Series: New feature -""" \ No newline at end of file +""" diff --git a/pandas_ta/volatility/pdist.py b/pandas_ta/volatility/pdist.py index f90e115..7218847 100644 --- a/pandas_ta/volatility/pdist.py +++ b/pandas_ta/volatility/pdist.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from ..utils import get_drift, get_offset, non_zero_range, verify_series + def pdist(open_, high, low, close, drift=None, offset=None, **kwargs): """Indicator: Price Distance (PDIST)""" # Validate Arguments @@ -27,9 +28,7 @@ def pdist(open_, high, low, close, drift=None, offset=None, **kwargs): return pdist - -pdist.__doc__ = \ -"""Price Distance (PDIST) +pdist.__doc__ = """Price Distance (PDIST) Measures the "distance" covered by price movements. @@ -56,4 +55,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/volatility/rvi.py b/pandas_ta/volatility/rvi.py index 9a11536..1e017a4 100644 --- a/pandas_ta/volatility/rvi.py +++ b/pandas_ta/volatility/rvi.py @@ -2,10 +2,28 @@ from pandas import DataFrame from pandas_ta.overlap import ema, sma from pandas_ta.statistics import stdev -from pandas_ta.utils import get_drift, get_offset, non_zero_range, unsigned_differences, verify_series +from pandas_ta.utils import ( + get_drift, + get_offset, + non_zero_range, + unsigned_differences, + verify_series, +) -def rvi(close, high=None, low=None, length=None, scalar=None, refined=None, thirds=None, mamode=None, drift=None, offset=None, **kwargs): +def rvi( + close, + high=None, + low=None, + length=None, + scalar=None, + refined=None, + thirds=None, + mamode=None, + drift=None, + offset=None, + **kwargs, +): """Indicator: Relative Volatility Index (RVI)""" # Validate arguments close = verify_series(close) @@ -33,7 +51,7 @@ def rvi(close, high=None, low=None, length=None, scalar=None, refined=None, thir if mamode == "sma": pos_avg = sma(pos_std, length) neg_avg = sma(neg_std, length) - else: # "ema" + else: # "ema" pos_avg = ema(pos_std, length) neg_avg = ema(neg_std, length) @@ -51,7 +69,7 @@ def rvi(close, high=None, low=None, length=None, scalar=None, refined=None, thir high_rvi = rvi_(high, length, scalar, mamode, drift) low_rvi = rvi_(low, length, scalar, mamode, drift) close_rvi = rvi_(close, length, scalar, mamode, drift) - rvi = (high_rvi + low_rvi + close_rvi) / 3. + rvi = (high_rvi + low_rvi + close_rvi) / 3.0 _mode = "t" else: rvi = rvi_(close, length, scalar, mamode, drift) @@ -73,9 +91,7 @@ def rvi(close, high=None, low=None, length=None, scalar=None, refined=None, thir return rvi - -rvi.__doc__ = \ -"""Relative Volatility Index (RVI) +rvi.__doc__ = """Relative Volatility Index (RVI) The Relative Volatility Index (RVI) was created in 1993 and revised in 1995. Instead of adding up price changes like RSI @@ -117,4 +133,4 @@ Kwargs: Returns: pd.DataFrame: lower, basis, upper columns. -""" \ No newline at end of file +""" diff --git a/pandas_ta/volatility/true_range.py b/pandas_ta/volatility/true_range.py index f7c6ad3..209272a 100644 --- a/pandas_ta/volatility/true_range.py +++ b/pandas_ta/volatility/true_range.py @@ -2,6 +2,7 @@ from pandas import DataFrame from ..utils import get_drift, get_offset, non_zero_range, verify_series + def true_range(high, low, close, drift=None, offset=None, **kwargs): """Indicator: True Range""" # Validate arguments @@ -35,9 +36,7 @@ def true_range(high, low, close, drift=None, offset=None, **kwargs): return true_range - -true_range.__doc__ = \ -"""True Range +true_range.__doc__ = """True Range An method to expand a classical range (high minus low) to include possible gap scenarios. @@ -50,7 +49,7 @@ Calculation: drift=1 ABS = Absolute Value prev_close = close.shift(drift) - TRUE_RANGE = ABS([high - low, high - prev_close, low - prev_close]) + TRUE_RANGE = ABS([high - low, high - prev_close, low - prev_close]) Args: high (pd.Series): Series of 'high's @@ -65,4 +64,4 @@ Kwargs: Returns: pd.Series: New feature -""" \ No newline at end of file +""" diff --git a/pandas_ta/volatility/ui.py b/pandas_ta/volatility/ui.py index 2ad827e..1d70d57 100644 --- a/pandas_ta/volatility/ui.py +++ b/pandas_ta/volatility/ui.py @@ -42,9 +42,7 @@ def ui(close, length=None, scalar=None, offset=None, **kwargs): return ui - -ui.__doc__ = \ -"""Ulcer Index (UI) +ui.__doc__ = """Ulcer Index (UI) The Ulcer Index by Peter Martin measures the downside volatility with the use of the Quadratic Mean, which has the effect of emphasising large drawdowns. @@ -82,4 +80,4 @@ Kwargs: Returns: pd.Series: New feature -""" \ No newline at end of file +""" diff --git a/pandas_ta/volume/__init__.py b/pandas_ta/volume/__init__.py index c8f8981..bd1e2c3 100644 --- a/pandas_ta/volume/__init__.py +++ b/pandas_ta/volume/__init__.py @@ -11,4 +11,4 @@ from .obv import obv from .pvi import pvi from .pvol import pvol from .pvt import pvt -from .vp import vp \ No newline at end of file +from .vp import vp diff --git a/pandas_ta/volume/ad.py b/pandas_ta/volume/ad.py index c8676e2..4c7dc8f 100644 --- a/pandas_ta/volume/ad.py +++ b/pandas_ta/volume/ad.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, non_zero_range, verify_series + def ad(high, low, close, volume, open_=None, offset=None, **kwargs): """Indicator: Accumulation/Distribution (AD)""" # Validate Arguments @@ -14,7 +15,7 @@ def ad(high, low, close, volume, open_=None, offset=None, **kwargs): # Calculate Result if open_ is not None: open_ = verify_series(open_) - ad = non_zero_range(close, open_) # AD with Open + ad = non_zero_range(close, open_) # AD with Open else: ad = 2 * close - (high + low) # AD with High, Low, Close @@ -38,9 +39,7 @@ def ad(high, low, close, volume, open_=None, offset=None, **kwargs): return ad - -ad.__doc__ = \ -"""Accumulation/Distribution (AD) +ad.__doc__ = """Accumulation/Distribution (AD) Accumulation/Distribution indicator utilizes the relative position of the close to it's High-Low range with volume. Then it is cumulated. @@ -73,4 +72,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/volume/adosc.py b/pandas_ta/volume/adosc.py index b19233b..a9d222a 100644 --- a/pandas_ta/volume/adosc.py +++ b/pandas_ta/volume/adosc.py @@ -3,7 +3,16 @@ from .ad import ad from ..overlap.ema import ema from ..utils import get_offset, verify_series -def adosc(high, low, close, volume, open_=None, fast=None, slow=None, offset=None, **kwargs): + +def adosc(high, + low, + close, + volume, + open_=None, + fast=None, + slow=None, + offset=None, + **kwargs): """Indicator: Accumulation/Distribution Oscillator""" # Validate Arguments high = verify_series(high) @@ -37,11 +46,9 @@ def adosc(high, low, close, volume, open_=None, fast=None, slow=None, offset=Non return adosc +adosc.__doc__ = """Accumulation/Distribution Oscillator or Chaikin Oscillator -adosc.__doc__ = \ -"""Accumulation/Distribution Oscillator or Chaikin Oscillator - -Accumulation/Distribution Oscillator indicator utilizes +Accumulation/Distribution Oscillator indicator utilizes Accumulation/Distribution and treats it similarily to MACD or APO. @@ -73,4 +80,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/volume/aobv.py b/pandas_ta/volume/aobv.py index 31ba3e2..fcc56f8 100644 --- a/pandas_ta/volume/aobv.py +++ b/pandas_ta/volume/aobv.py @@ -5,7 +5,18 @@ from pandas_ta.overlap import ema, hma, linreg, sma, wma from pandas_ta.trend import long_run, short_run from pandas_ta.utils import get_offset, verify_series -def aobv(close, volume, fast=None, slow=None, mamode=None, max_lookback=None, min_lookback=None, offset=None, **kwargs): + +def aobv( + close, + volume, + fast=None, + slow=None, + mamode=None, + max_lookback=None, + min_lookback=None, + offset=None, + **kwargs, +): """Indicator: Archer On Balance Volume (AOBV)""" # Validate arguments close = verify_series(close) @@ -73,12 +84,14 @@ def aobv(close, volume, fast=None, slow=None, mamode=None, max_lookback=None, mi f"OBV_{maf.name}": maf, f"OBV_{mas.name}": mas, f"AOBV_LR_{run_length}": obv_long, - f"AOBV_SR_{run_length}": obv_short + f"AOBV_SR_{run_length}": obv_short, } aobvdf = DataFrame(data) # Name and Categorize it - aobvdf.name = f"AOBV_{mamode}_{fast}_{slow}_{min_lookback}_{max_lookback}_{run_length}" + aobvdf.name = ( + f"AOBV_{mamode}_{fast}_{slow}_{min_lookback}_{max_lookback}_{run_length}" + ) aobvdf.category = "volume" return aobvdf diff --git a/pandas_ta/volume/cmf.py b/pandas_ta/volume/cmf.py index 62d1cf7..6cebc50 100644 --- a/pandas_ta/volume/cmf.py +++ b/pandas_ta/volume/cmf.py @@ -1,7 +1,15 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, non_zero_range, verify_series -def cmf(high, low, close, volume, open_=None, length=None, offset=None, **kwargs): + +def cmf(high, + low, + close, + volume, + open_=None, + length=None, + offset=None, + **kwargs): """Indicator: Chaikin Money Flow (CMF)""" # Validate Arguments high = verify_series(high) @@ -10,14 +18,15 @@ def cmf(high, low, close, volume, open_=None, length=None, offset=None, **kwargs volume = verify_series(volume) high_low_range = non_zero_range(high, low) length = int(length) if length and length > 0 else 20 - min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) offset = get_offset(offset) # Calculate Result if open_ is not None: open_ = verify_series(open_) - ad = non_zero_range(close, open_) # AD with Open - else: + ad = non_zero_range(close, open_) # AD with Open + else: ad = 2 * close - (high + low) # AD with High, Low, Close ad *= volume / high_low_range @@ -41,9 +50,7 @@ def cmf(high, low, close, volume, open_=None, length=None, offset=None, **kwargs return cmf - -cmf.__doc__ = \ -"""Chaikin Money Flow (CMF) +cmf.__doc__ = """Chaikin Money Flow (CMF) Chailin Money Flow measures the amount of money flow volume over a specific period in conjunction with Accumulation/Distribution. @@ -59,7 +66,7 @@ Calculation: ad = close - open else: ad = 2 * close - high - low - + hl_range = high - low ad = ad * volume / hl_range CMF = SUM(ad, length) / SUM(volume, length) diff --git a/pandas_ta/volume/efi.py b/pandas_ta/volume/efi.py index 6939d13..15e4179 100644 --- a/pandas_ta/volume/efi.py +++ b/pandas_ta/volume/efi.py @@ -2,7 +2,14 @@ from pandas_ta.overlap import ema, sma from pandas_ta.utils import get_drift, get_offset, verify_series -def efi(close, volume, length=None, drift=None, mamode=None, offset=None, **kwargs): + +def efi(close, + volume, + length=None, + drift=None, + mamode=None, + offset=None, + **kwargs): """Indicator: Elder's Force Index (EFI)""" # Validate arguments close = verify_series(close) @@ -37,9 +44,7 @@ def efi(close, volume, length=None, drift=None, mamode=None, offset=None, **kwar return efi - -efi.__doc__ = \ -"""Elder's Force Index (EFI) +efi.__doc__ = """Elder's Force Index (EFI) Elder's Force Index measures the power behind a price movement using price and volume as well as potential reversals and price corrections. @@ -74,4 +79,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/volume/eom.py b/pandas_ta/volume/eom.py index d11085b..32a5d7b 100644 --- a/pandas_ta/volume/eom.py +++ b/pandas_ta/volume/eom.py @@ -2,7 +2,18 @@ from pandas_ta.overlap import hl2, sma from pandas_ta.utils import get_drift, get_offset, non_zero_range, verify_series -def eom(high, low, close, volume, length=None, divisor=None, drift=None, offset=None, **kwargs): + +def eom( + high, + low, + close, + volume, + length=None, + divisor=None, + drift=None, + offset=None, + **kwargs, +): """Indicator: Ease of Movement (EOM)""" # Validate arguments high = verify_series(high) @@ -16,7 +27,8 @@ def eom(high, low, close, volume, length=None, divisor=None, drift=None, offset= # Calculate Result high_low_range = non_zero_range(high, low) - distance = hl2(high=high, low=low) - hl2(high=high.shift(drift), low=low.shift(drift)) + distance = hl2(high=high, low=low) - hl2(high=high.shift(drift), + low=low.shift(drift)) box_ratio = volume / divisor box_ratio /= high_low_range eom = distance / box_ratio @@ -39,9 +51,7 @@ def eom(high, low, close, volume, length=None, divisor=None, drift=None, offset= return eom - -eom.__doc__ = \ -"""Ease of Movement (EOM) +eom.__doc__ = """Ease of Movement (EOM) Ease of Movement is a volume based oscillator that is designed to measure the relationship between price and volume flucuating across a zero line. @@ -54,7 +64,7 @@ Sources: Calculation: Default Inputs: length=14, divisor=100000000, drift=1 - SMA = Simple Moving Average + SMA = Simple Moving Average hl_range = high - low distance = 0.5 * (high - high.shift(drift) + low - low.shift(drift)) box_ratio = (volume / divisor) / hl_range @@ -76,4 +86,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/volume/mfi.py b/pandas_ta/volume/mfi.py index 9082e23..c8560a2 100644 --- a/pandas_ta/volume/mfi.py +++ b/pandas_ta/volume/mfi.py @@ -3,7 +3,15 @@ from pandas import DataFrame from ..overlap.hlc3 import hlc3 from ..utils import get_drift, get_offset, verify_series -def mfi(high, low, close, volume, length=None, drift=None, offset=None, **kwargs): + +def mfi(high, + low, + close, + volume, + length=None, + drift=None, + offset=None, + **kwargs): """Indicator: Money Flow Index (MFI)""" # Validate arguments high = verify_series(high) @@ -20,8 +28,8 @@ def mfi(high, low, close, volume, length=None, drift=None, offset=None, **kwargs tdf = DataFrame({"diff": 0, "rmf": raw_money_flow, "+mf": 0, "-mf": 0}) - tdf.loc[(typical_price.diff(drift) > 0), "diff"] = 1 - tdf.loc[tdf["diff"] == 1, "+mf"] = raw_money_flow + tdf.loc[(typical_price.diff(drift) > 0), "diff"] = 1 + tdf.loc[tdf["diff"] == 1, "+mf"] = raw_money_flow tdf.loc[(typical_price.diff(drift) < 0), "diff"] = -1 tdf.loc[tdf["diff"] == -1, "-mf"] = raw_money_flow @@ -49,9 +57,7 @@ def mfi(high, low, close, volume, length=None, drift=None, offset=None, **kwargs return mfi - -mfi.__doc__ = \ -"""Money Flow Index (MFI) +mfi.__doc__ = """Money Flow Index (MFI) Money Flow Index is an oscillator indicator that is used to measure buying and selling pressure by utilizing both price and volume. @@ -86,4 +92,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/volume/nvi.py b/pandas_ta/volume/nvi.py index 4868ae5..7ce3cb0 100644 --- a/pandas_ta/volume/nvi.py +++ b/pandas_ta/volume/nvi.py @@ -2,13 +2,15 @@ from ..momentum.roc import roc from ..utils import get_offset, signed_series, verify_series + def nvi(close, volume, length=None, initial=None, offset=None, **kwargs): """Indicator: Negative Volume Index (NVI)""" # Validate arguments close = verify_series(close) volume = verify_series(volume) length = int(length) if length and length > 0 else 1 - min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) initial = int(initial) if initial and initial > 0 else 1000 offset = get_offset(offset) @@ -17,7 +19,7 @@ def nvi(close, volume, length=None, initial=None, offset=None, **kwargs): signed_volume = signed_series(volume, initial=1) nvi = signed_volume[signed_volume < 0].abs() * roc_ nvi.fillna(0, inplace=True) - nvi.iloc[0]= initial + nvi.iloc[0] = initial nvi = nvi.cumsum() # Offset @@ -37,9 +39,7 @@ def nvi(close, volume, length=None, initial=None, offset=None, **kwargs): return nvi - -nvi.__doc__ = \ -"""Negative Volume Index (NVI) +nvi.__doc__ = """Negative Volume Index (NVI) The Negative Volume Index is a cumulative indicator that uses volume change in an attempt to identify where smart money is active. @@ -73,4 +73,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/volume/obv.py b/pandas_ta/volume/obv.py index 079d4cf..e682079 100644 --- a/pandas_ta/volume/obv.py +++ b/pandas_ta/volume/obv.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, signed_series, verify_series + def obv(close, volume, offset=None, **kwargs): """Indicator: On Balance Volume (OBV)""" # Validate arguments @@ -29,9 +30,7 @@ def obv(close, volume, offset=None, **kwargs): return obv - -obv.__doc__ = \ -"""On Balance Volume (OBV) +obv.__doc__ = """On Balance Volume (OBV) On Balance Volume is a cumulative indicator to measure buying and selling pressure. @@ -56,4 +55,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/volume/pvi.py b/pandas_ta/volume/pvi.py index b56fc88..ae48ea7 100644 --- a/pandas_ta/volume/pvi.py +++ b/pandas_ta/volume/pvi.py @@ -2,13 +2,15 @@ from ..momentum.roc import roc from ..utils import get_offset, signed_series, verify_series + def pvi(close, volume, length=None, initial=None, offset=None, **kwargs): """Indicator: Positive Volume Index (PVI)""" # Validate arguments close = verify_series(close) volume = verify_series(volume) length = int(length) if length and length > 0 else 1 - min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length + min_periods = (int(kwargs["min_periods"]) if "min_periods" in kwargs and + kwargs["min_periods"] is not None else length) initial = int(initial) if initial and initial > 0 else 1000 offset = get_offset(offset) @@ -17,7 +19,7 @@ def pvi(close, volume, length=None, initial=None, offset=None, **kwargs): signed_volume = signed_series(volume, initial=1) pvi = signed_volume[signed_volume > 0].abs() * roc_ pvi.fillna(0, inplace=True) - pvi.iloc[0]= initial + pvi.iloc[0] = initial pvi = pvi.cumsum() # Offset @@ -37,9 +39,7 @@ def pvi(close, volume, length=None, initial=None, offset=None, **kwargs): return pvi - -pvi.__doc__ = \ -"""Positive Volume Index (PVI) +pvi.__doc__ = """Positive Volume Index (PVI) The Positive Volume Index is a cumulative indicator that uses volume change in an attempt to identify where smart money is active. Used in conjunction with NVI. @@ -72,4 +72,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/volume/pvol.py b/pandas_ta/volume/pvol.py index 952dc06..9448148 100644 --- a/pandas_ta/volume/pvol.py +++ b/pandas_ta/volume/pvol.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from ..utils import get_offset, signed_series, verify_series + def pvol(close, volume, offset=None, **kwargs): """Indicator: Price-Volume (PVOL)""" # Validate arguments @@ -32,9 +33,7 @@ def pvol(close, volume, offset=None, **kwargs): return pvol - -pvol.__doc__ = \ -"""Price-Volume (PVOL) +pvol.__doc__ = """Price-Volume (PVOL) Returns a series of the product of price and volume. @@ -56,4 +55,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/volume/pvt.py b/pandas_ta/volume/pvt.py index 23851d7..ed42945 100644 --- a/pandas_ta/volume/pvt.py +++ b/pandas_ta/volume/pvt.py @@ -2,6 +2,7 @@ from ..momentum.roc import roc from ..utils import get_drift, get_offset, verify_series + def pvt(close, volume, drift=None, offset=None, **kwargs): """Indicator: Price-Volume Trend (PVT)""" # Validate arguments @@ -31,9 +32,7 @@ def pvt(close, volume, drift=None, offset=None, **kwargs): return pvt - -pvt.__doc__ = \ -"""Price-Volume Trend (PVT) +pvt.__doc__ = """Price-Volume Trend (PVT) The Price-Volume Trend utilizes the Rate of Change with volume to and it's cumulative values to determine money flow. @@ -60,4 +59,4 @@ Kwargs: Returns: pd.Series: New feature generated. -""" \ No newline at end of file +""" diff --git a/pandas_ta/volume/vp.py b/pandas_ta/volume/vp.py index 96a72a5..5f45a08 100644 --- a/pandas_ta/volume/vp.py +++ b/pandas_ta/volume/vp.py @@ -3,6 +3,7 @@ from numpy import array_split from pandas import concat, DataFrame from ..utils import signed_series, verify_series + def vp(close, volume, width=None, **kwargs): """Indicator: Volume Profile (VP)""" # Validate arguments @@ -59,8 +60,7 @@ def vp(close, volume, width=None, **kwargs): return vpdf -vp.__doc__ = \ -"""Volume Profile (VP) +vp.__doc__ = """Volume Profile (VP) Calculates the Volume Profile by slicing price into ranges. Note: Value Area is not calculated. @@ -73,7 +73,7 @@ Sources: Calculation: Default Inputs: width=10 - + vp = pd.concat([close, pos_volume, neg_volume], axis=1) vp_ranges = np.array_split(vp, width) result = ({high_close, low_close, mean_close, neg_volume, pos_volume} foreach range in vp_ranges) @@ -92,4 +92,4 @@ Kwargs: Returns: pd.DataFrame: New feature generated. -""" \ No newline at end of file +""" diff --git a/setup.py b/setup.py index a15acbe..ae55603 100644 --- a/setup.py +++ b/setup.py @@ -4,21 +4,32 @@ from distutils.core import setup long_description = "An easy to use Python 3 Pandas Extension with 115+ Technical Analysis Indicators. Can be called from a Pandas DataFrame or standalone like TA-Lib. Correlation tested with TA-Lib." setup( - name ="pandas_ta", - packages =["pandas_ta", "pandas_ta.candles", "pandas_ta.momentum", "pandas_ta.overlap", "pandas_ta.performance", "pandas_ta.statistics", "pandas_ta.trend", "pandas_ta.utils", "pandas_ta.volatility", "pandas_ta.volume"], - version =".".join(("0", "2", "15b")), - description =long_description, - long_description =long_description, - author ="Kevin Johnson", - author_email ="appliedmathkj@gmail.com", - url ="https://github.com/twopirllc/pandas-ta", - maintainer ="Kevin Johnson", - maintainer_email ="appliedmathkj@gmail.com", + name="pandas_ta", + packages=[ + "pandas_ta", + "pandas_ta.candles", + "pandas_ta.momentum", + "pandas_ta.overlap", + "pandas_ta.performance", + "pandas_ta.statistics", + "pandas_ta.trend", + "pandas_ta.utils", + "pandas_ta.volatility", + "pandas_ta.volume", + ], + version=".".join(("0", "2", "15b")), + description=long_description, + long_description=long_description, + author="Kevin Johnson", + author_email="appliedmathkj@gmail.com", + url="https://github.com/twopirllc/pandas-ta", + maintainer="Kevin Johnson", + maintainer_email="appliedmathkj@gmail.com", # install_requires=["pandas"], - download_url ="https://github.com/twopirllc/pandas-ta.git", - keywords =["technical analysis", "trading", "python3", "pandas"], - license ="The MIT License (MIT)", - classifiers =[ + download_url="https://github.com/twopirllc/pandas-ta.git", + keywords=["technical analysis", "trading", "python3", "pandas"], + license="The MIT License (MIT)", + classifiers=[ "Development Status :: 4 - Beta", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", @@ -37,12 +48,11 @@ setup( package_data={ "data": ["data/*.csv"], }, - install_requires =["pandas"], - + install_requires=["pandas"], # List additional groups of dependencies here (e.g. development dependencies). # You can install these using the following syntax, for example: # $ pip install -e .[dev,test] - extras_require = { + extras_require={ "dev": ["ta-lib", "jupyterlab", "sklearn", "statsmodels"], "test": ["ta-lib"], }, diff --git a/tests/config.py b/tests/config.py index 0f6c911..e9d373e 100644 --- a/tests/config.py +++ b/tests/config.py @@ -6,22 +6,25 @@ VERBOSE = True ALERT = f"[!]" INFO = f"[i]" -CORRELATION = "corr" #"sem" +CORRELATION = "corr" # "sem" CORRELATION_THRESHOLD = 0.99 # Less than 0.99 is undesirable sample_data = read_csv( - f"data/SPY_D.csv", - index_col=0, - parse_dates=True, - infer_datetime_format=True, - keep_date_col=True - ) -sample_data.set_index(DatetimeIndex(sample_data["date"]), inplace=True, drop=True) + f"data/SPY_D.csv", + index_col=0, + parse_dates=True, + infer_datetime_format=True, + keep_date_col=True, +) +sample_data.set_index(DatetimeIndex(sample_data["date"]), + inplace=True, + drop=True) sample_data.drop("date", axis=1, inplace=True) def error_analysis(df, kind, msg, icon=INFO, newline=True): if VERBOSE: s = f"{icon} {df.name}['{kind}']: {msg}" - if newline: s = f"\n{s}" - print(s) \ No newline at end of file + if newline: + s = f"\n{s}" + print(s) diff --git a/tests/context.py b/tests/context.py index 11f5534..66ef8ea 100644 --- a/tests/context.py +++ b/tests/context.py @@ -1,5 +1,7 @@ import os import sys -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) -import pandas_ta \ No newline at end of file +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), + ".."))) + +import pandas_ta diff --git a/tests/test_ext_indicator_candle.py b/tests/test_ext_indicator_candle.py index ce8f9e5..bd8d621 100644 --- a/tests/test_ext_indicator_candle.py +++ b/tests/test_ext_indicator_candle.py @@ -5,8 +5,8 @@ from unittest import TestCase from pandas import DataFrame - class TestCandleExtension(TestCase): + @classmethod def setUpClass(cls): cls.data = sample_data @@ -15,9 +15,11 @@ class TestCandleExtension(TestCase): def tearDownClass(cls): del cls.data - def setUp(self): pass - def tearDown(self): pass + def setUp(self): + pass + def tearDown(self): + pass def test_cdl_doji_ext(self): self.data.ta.cdl_doji(append=True) @@ -32,4 +34,5 @@ class TestCandleExtension(TestCase): def test_ha_ext(self): self.data.ta.ha(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-4:]), ["HA_open", "HA_high", "HA_low", "HA_close"]) \ No newline at end of file + self.assertEqual(list(self.data.columns[-4:]), + ["HA_open", "HA_high", "HA_low", "HA_close"]) diff --git a/tests/test_ext_indicator_momentum.py b/tests/test_ext_indicator_momentum.py index cb463a4..c052fd2 100644 --- a/tests/test_ext_indicator_momentum.py +++ b/tests/test_ext_indicator_momentum.py @@ -5,8 +5,8 @@ from unittest import skip, TestCase from pandas import DataFrame - class TestMomentumExtension(TestCase): + @classmethod def setUpClass(cls): cls.data = sample_data @@ -15,9 +15,11 @@ class TestMomentumExtension(TestCase): def tearDownClass(cls): del cls.data - def setUp(self): pass - def tearDown(self): pass + def setUp(self): + pass + def tearDown(self): + pass def test_ao_ext(self): self.data.ta.ao(append=True) @@ -82,7 +84,8 @@ class TestMomentumExtension(TestCase): def test_fisher_ext(self): self.data.ta.fisher(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-2:]), ["FISHERT_9_1", "FISHERTs_9_1"]) + self.assertEqual(list(self.data.columns[-2:]), + ["FISHERT_9_1", "FISHERTs_9_1"]) def test_inertia_ext(self): self.data.ta.inertia(append=True) @@ -102,17 +105,22 @@ class TestMomentumExtension(TestCase): def test_kdj_ext(self): self.data.ta.kdj(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-3:]), ["K_9_3", "D_9_3", "J_9_3"]) + self.assertEqual(list(self.data.columns[-3:]), + ["K_9_3", "D_9_3", "J_9_3"]) def test_kst_ext(self): self.data.ta.kst(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-2:]), ["KST_10_15_20_30_10_10_10_15", "KSTs_9"]) + self.assertEqual(list(self.data.columns[-2:]), + ["KST_10_15_20_30_10_10_10_15", "KSTs_9"]) def test_macd_ext(self): self.data.ta.macd(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-3:]), ["MACD_12_26_9", "MACDh_12_26_9", "MACDs_12_26_9"]) + self.assertEqual( + list(self.data.columns[-3:]), + ["MACD_12_26_9", "MACDh_12_26_9", "MACDs_12_26_9"], + ) def test_mom_ext(self): self.data.ta.mom(append=True) @@ -127,7 +135,10 @@ class TestMomentumExtension(TestCase): def test_ppo_ext(self): self.data.ta.ppo(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-3:]), ["PPO_12_26_9", "PPOh_12_26_9", "PPOs_12_26_9"]) + self.assertEqual( + list(self.data.columns[-3:]), + ["PPO_12_26_9", "PPOh_12_26_9", "PPOs_12_26_9"], + ) def test_psl_ext(self): self.data.ta.psl(append=True) @@ -137,7 +148,10 @@ class TestMomentumExtension(TestCase): def test_pvo_ext(self): self.data.ta.pvo(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-3:]), ["PVO_12_26_9", "PVOh_12_26_9", "PVOs_12_26_9"]) + self.assertEqual( + list(self.data.columns[-3:]), + ["PVO_12_26_9", "PVOh_12_26_9", "PVOs_12_26_9"], + ) def test_roc_ext(self): self.data.ta.roc(append=True) @@ -152,7 +166,8 @@ class TestMomentumExtension(TestCase): def test_rvgi_ext(self): self.data.ta.rvgi(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-2:]), ["RVGI_14_4", "RVGIs_14_4"]) + self.assertEqual(list(self.data.columns[-2:]), + ["RVGI_14_4", "RVGIs_14_4"]) def test_slope_ext(self): self.data.ta.slope(append=True) @@ -170,35 +185,48 @@ class TestMomentumExtension(TestCase): def test_smi_ext(self): self.data.ta.smi(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-3:]), ["SMI_5_20_5", "SMIs_5_20_5", "SMIo_5_20_5"]) + self.assertEqual(list(self.data.columns[-3:]), + ["SMI_5_20_5", "SMIs_5_20_5", "SMIo_5_20_5"]) self.data.ta.smi(scalar=10, append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-3:]), ["SMI_5_20_5_10.0", "SMIs_5_20_5_10.0", "SMIo_5_20_5_10.0"]) + self.assertEqual( + list(self.data.columns[-3:]), + ["SMI_5_20_5_10.0", "SMIs_5_20_5_10.0", "SMIo_5_20_5_10.0"], + ) def test_squeeze_ext(self): self.data.ta.squeeze(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-4:]), ["SQZ_20_2.0_20_1.5", "SQZ_ON", "SQZ_OFF", "SQZ_NO"]) + self.assertEqual( + list(self.data.columns[-4:]), + ["SQZ_20_2.0_20_1.5", "SQZ_ON", "SQZ_OFF", "SQZ_NO"], + ) self.data.ta.squeeze(tr=False, append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-4:]), ["SQZ_ON", "SQZ_OFF", "SQZ_NO", "SQZhlr_20_2.0_20_1.5"]) + self.assertEqual( + list(self.data.columns[-4:]), + ["SQZ_ON", "SQZ_OFF", "SQZ_NO", "SQZhlr_20_2.0_20_1.5"], + ) def test_stoch_ext(self): self.data.ta.stoch(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-2:]), ["STOCHk_14_3_3", "STOCHd_14_3_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"]) + 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) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-2:]), ["TRIX_30_9", "TRIXs_30_9"]) + self.assertEqual(list(self.data.columns[-2:]), + ["TRIX_30_9", "TRIXs_30_9"]) def test_tsi_ext(self): self.data.ta.tsi(append=True) diff --git a/tests/test_ext_indicator_overlap_ext.py b/tests/test_ext_indicator_overlap_ext.py index 7da8341..21f556c 100644 --- a/tests/test_ext_indicator_overlap_ext.py +++ b/tests/test_ext_indicator_overlap_ext.py @@ -5,8 +5,8 @@ from unittest import skip, TestCase from pandas import DataFrame - class TestOverlapExtension(TestCase): + @classmethod def setUpClass(cls): cls.data = sample_data @@ -15,9 +15,11 @@ class TestOverlapExtension(TestCase): def tearDownClass(cls): del cls.data - def setUp(self): pass - def tearDown(self): pass + def setUp(self): + pass + def tearDown(self): + pass def test_dema_ext(self): self.data.ta.dema(append=True) @@ -37,7 +39,8 @@ class TestOverlapExtension(TestCase): def test_hilo_ext(self): self.data.ta.hilo(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-3:]), ["HILO_13_21", "HILOl_13_21", "HILOs_13_21"]) + self.assertEqual(list(self.data.columns[-3:]), + ["HILO_13_21", "HILOl_13_21", "HILOs_13_21"]) def test_hl2_ext(self): self.data.ta.hl2(append=True) @@ -62,7 +65,10 @@ class TestOverlapExtension(TestCase): def test_ichimoku_ext(self): self.data.ta.ichimoku(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-5:]), ["ISA_9", "ISB_26", "ITS_9", "IKS_26", "ICS_26"]) + self.assertEqual( + list(self.data.columns[-5:]), + ["ISA_9", "ISB_26", "ITS_9", "IKS_26", "ICS_26"], + ) def test_linreg_ext(self): self.data.ta.linreg(append=True) @@ -112,7 +118,10 @@ class TestOverlapExtension(TestCase): def test_supertrend_ext(self): self.data.ta.supertrend(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-4:]), ["SUPERT_7_3.0", "SUPERTd_7_3.0", "SUPERTl_7_3.0", "SUPERTs_7_3.0"]) + self.assertEqual( + list(self.data.columns[-4:]), + ["SUPERT_7_3.0", "SUPERTd_7_3.0", "SUPERTl_7_3.0", "SUPERTs_7_3.0"], + ) def test_t3_ext(self): self.data.ta.t3(append=True) @@ -152,4 +161,4 @@ class TestOverlapExtension(TestCase): def test_zlma_ext(self): self.data.ta.zlma(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(self.data.columns[-1], "ZL_EMA_10") \ No newline at end of file + self.assertEqual(self.data.columns[-1], "ZL_EMA_10") diff --git a/tests/test_ext_indicator_performance.py b/tests/test_ext_indicator_performance.py index bbabc74..4a68861 100644 --- a/tests/test_ext_indicator_performance.py +++ b/tests/test_ext_indicator_performance.py @@ -5,21 +5,24 @@ from unittest import TestCase from pandas import DataFrame - class TestPerformaceExtension(TestCase): + @classmethod def setUpClass(cls): cls.data = sample_data - cls.islong = cls.data["close"] > pandas_ta.sma(cls.data["close"], length=50) + cls.islong = cls.data["close"] > pandas_ta.sma(cls.data["close"], + length=50) @classmethod def tearDownClass(cls): del cls.data del cls.islong - def setUp(self): pass - def tearDown(self): pass + def setUp(self): + pass + def tearDown(self): + pass def test_log_return_ext(self): self.data.ta.log_return(append=True) @@ -42,17 +45,29 @@ class TestPerformaceExtension(TestCase): self.assertEqual(self.data.columns[-1], "CUMPCTRET_1") def test_log_trend_return_ext(self): - self.data.ta.trend_return(trend=self.islong, log=True, cumulative=False, append=True) + self.data.ta.trend_return(trend=self.islong, + log=True, + cumulative=False, + append=True) self.assertIsInstance(self.data, DataFrame) def test_cum_log_trend_return_ext(self): - self.data.ta.trend_return(trend=self.islong, log=True, cumulative=True, append=True) + self.data.ta.trend_return(trend=self.islong, + log=True, + cumulative=True, + append=True) self.assertIsInstance(self.data, DataFrame) def test_pct_trend_return_ext(self): - self.data.ta.trend_return(trend=self.islong, log=False, cumulative=False, append=True) + self.data.ta.trend_return(trend=self.islong, + log=False, + cumulative=False, + append=True) self.assertIsInstance(self.data, DataFrame) def test_cum_pct_trend_return_ext(self): - self.data.ta.trend_return(trend=self.islong, log=False, cumulative=True, append=True) - self.assertIsInstance(self.data, DataFrame) \ No newline at end of file + self.data.ta.trend_return(trend=self.islong, + log=False, + cumulative=True, + append=True) + self.assertIsInstance(self.data, DataFrame) diff --git a/tests/test_ext_indicator_statistics.py b/tests/test_ext_indicator_statistics.py index f0f5013..5cff9b8 100644 --- a/tests/test_ext_indicator_statistics.py +++ b/tests/test_ext_indicator_statistics.py @@ -5,8 +5,8 @@ from unittest import TestCase from pandas import DataFrame - class TestStatisticsExtension(TestCase): + @classmethod def setUpClass(cls): cls.data = sample_data @@ -15,9 +15,11 @@ class TestStatisticsExtension(TestCase): def tearDownClass(cls): del cls.data - def setUp(self): pass - def tearDown(self): pass + def setUp(self): + pass + def tearDown(self): + pass def test_entropy_ext(self): self.data.ta.entropy(append=True) diff --git a/tests/test_ext_indicator_trend.py b/tests/test_ext_indicator_trend.py index b38c392..e3df137 100644 --- a/tests/test_ext_indicator_trend.py +++ b/tests/test_ext_indicator_trend.py @@ -5,8 +5,8 @@ from unittest import skip, TestCase from pandas import DataFrame - class TestTrendExtension(TestCase): + @classmethod def setUpClass(cls): cls.data = sample_data @@ -15,24 +15,29 @@ class TestTrendExtension(TestCase): def tearDownClass(cls): del cls.data - def setUp(self): pass - def tearDown(self): pass + def setUp(self): + pass + def tearDown(self): + pass def test_adx_ext(self): self.data.ta.adx(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-3:]), ["ADX_14", "DMP_14", "DMN_14"]) + self.assertEqual(list(self.data.columns[-3:]), + ["ADX_14", "DMP_14", "DMN_14"]) def test_amat_ext(self): self.data.ta.amat(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-2:]), ["AMAT_LR_2", "AMAT_SR_2"]) + self.assertEqual(list(self.data.columns[-2:]), + ["AMAT_LR_2", "AMAT_SR_2"]) def test_aroon_ext(self): self.data.ta.aroon(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-3:]), ["AROOND_14", "AROONU_14", "AROONOSC_14"]) + self.assertEqual(list(self.data.columns[-3:]), + ["AROOND_14", "AROONU_14", "AROONOSC_14"]) def test_chop_ext(self): self.data.ta.chop(append=True) @@ -70,7 +75,8 @@ class TestTrendExtension(TestCase): def test_long_run_ext(self): # Nothing passed, return self - self.assertEqual(self.data.ta.long_run(append=True).shape, self.data.shape) + self.assertEqual( + self.data.ta.long_run(append=True).shape, self.data.shape) fast = self.data.ta.ema(8) slow = self.data.ta.ema(21) @@ -81,7 +87,13 @@ class TestTrendExtension(TestCase): def test_psar_ext(self): self.data.ta.psar(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-4:]), ["PSARl_0.02_0.2", "PSARs_0.02_0.2", "PSARaf_0.02_0.2", "PSARr_0.02_0.2"]) + self.assertEqual( + list(self.data.columns[-4:]), + [ + "PSARl_0.02_0.2", "PSARs_0.02_0.2", "PSARaf_0.02_0.2", + "PSARr_0.02_0.2" + ], + ) def test_qstick_ext(self): self.data.ta.qstick(append=True) @@ -90,7 +102,8 @@ class TestTrendExtension(TestCase): def test_short_run_ext(self): # Nothing passed, return self - self.assertEqual(self.data.ta.short_run(append=True).shape, self.data.shape) + self.assertEqual( + self.data.ta.short_run(append=True).shape, self.data.shape) fast = self.data.ta.ema(8) slow = self.data.ta.ema(21) diff --git a/tests/test_ext_indicator_volatility.py b/tests/test_ext_indicator_volatility.py index ad09b10..081c26b 100644 --- a/tests/test_ext_indicator_volatility.py +++ b/tests/test_ext_indicator_volatility.py @@ -5,8 +5,8 @@ from unittest import TestCase from pandas import DataFrame - class TestVolatilityExtension(TestCase): + @classmethod def setUpClass(cls): cls.data = sample_data @@ -15,19 +15,25 @@ class TestVolatilityExtension(TestCase): def tearDownClass(cls): del cls.data - def setUp(self): pass - def tearDown(self): pass + def setUp(self): + pass + def tearDown(self): + pass def test_aberration_ext(self): self.data.ta.aberration(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-4:]), ["ABER_ZG_5_15", "ABER_SG_5_15", "ABER_XG_5_15", "ABER_ATR_5_15"]) + self.assertEqual( + list(self.data.columns[-4:]), + ["ABER_ZG_5_15", "ABER_SG_5_15", "ABER_XG_5_15", "ABER_ATR_5_15"], + ) def test_accbands_ext(self): self.data.ta.accbands(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-3:]), ["ACCBL_20", "ACCBM_20", "ACCBU_20"]) + self.assertEqual(list(self.data.columns[-3:]), + ["ACCBL_20", "ACCBM_20", "ACCBU_20"]) def test_atr_ext(self): self.data.ta.atr(append=True) @@ -37,17 +43,20 @@ class TestVolatilityExtension(TestCase): def test_bbands_ext(self): self.data.ta.bbands(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-3:]), ["BBL_5_2.0", "BBM_5_2.0", "BBU_5_2.0"]) + self.assertEqual(list(self.data.columns[-3:]), + ["BBL_5_2.0", "BBM_5_2.0", "BBU_5_2.0"]) def test_donchian_ext(self): self.data.ta.donchian(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-3:]), ["DCL_20_20", "DCM_20_20", "DCU_20_20"]) + self.assertEqual(list(self.data.columns[-3:]), + ["DCL_20_20", "DCM_20_20", "DCU_20_20"]) def test_kc_ext(self): self.data.ta.kc(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-3:]), ["KCL_20_2", "KCB_20_2", "KCU_20_2"]) + self.assertEqual(list(self.data.columns[-3:]), + ["KCL_20_2", "KCB_20_2", "KCU_20_2"]) def test_massi_ext(self): self.data.ta.massi(append=True) @@ -91,4 +100,4 @@ class TestVolatilityExtension(TestCase): self.data.ta.ui(append=True, everget=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(self.data.columns[-1], "UIe_14") \ No newline at end of file + self.assertEqual(self.data.columns[-1], "UIe_14") diff --git a/tests/test_ext_indicator_volume.py b/tests/test_ext_indicator_volume.py index 9b0194e..96d4278 100644 --- a/tests/test_ext_indicator_volume.py +++ b/tests/test_ext_indicator_volume.py @@ -5,8 +5,8 @@ from unittest import TestCase from pandas import DataFrame - class TestVolumeExtension(TestCase): + @classmethod def setUpClass(cls): cls.data = sample_data @@ -17,9 +17,11 @@ class TestVolumeExtension(TestCase): del cls.data del cls.open - def setUp(self): pass - def tearDown(self): pass + def setUp(self): + pass + def tearDown(self): + pass def test_ad_ext(self): self.data.ta.ad(append=True) @@ -39,7 +41,18 @@ class TestVolumeExtension(TestCase): def test_aobv_ext(self): self.data.ta.aobv(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-7:]), ["OBV", "OBV_min_2", "OBV_max_2", "OBV_EMA_4", "OBV_EMA_12", "AOBV_LR_2", "AOBV_SR_2"]) + self.assertEqual( + list(self.data.columns[-7:]), + [ + "OBV", + "OBV_min_2", + "OBV_max_2", + "OBV_EMA_4", + "OBV_EMA_12", + "AOBV_LR_2", + "AOBV_SR_2", + ], + ) # Remove "OBV" so it does not interfere with test_obv_ext() self.data.drop("OBV", axis=1, inplace=True) @@ -95,4 +108,4 @@ class TestVolumeExtension(TestCase): def test_vp_ext(self): result = self.data.ta.vp() self.assertIsInstance(result, DataFrame) - self.assertEqual(result.name, "VP_10") \ No newline at end of file + self.assertEqual(result.name, "VP_10") diff --git a/tests/test_indicator_candle.py b/tests/test_indicator_candle.py index 661d335..b1903d2 100644 --- a/tests/test_indicator_candle.py +++ b/tests/test_indicator_candle.py @@ -1,4 +1,10 @@ -from .config import error_analysis, sample_data, CORRELATION, CORRELATION_THRESHOLD, VERBOSE +from .config import ( + error_analysis, + sample_data, + CORRELATION, + CORRELATION_THRESHOLD, + VERBOSE, +) from .context import pandas_ta from unittest import TestCase, skip @@ -8,8 +14,8 @@ from pandas import DataFrame, Series import talib as tal - class TestCandle(TestCase): + @classmethod def setUpClass(cls): cls.data = sample_data @@ -18,7 +24,8 @@ class TestCandle(TestCase): cls.high = cls.data["high"] cls.low = cls.data["low"] cls.close = cls.data["close"] - if "volume" in cls.data.columns: cls.volume = cls.data["volume"] + if "volume" in cls.data.columns: + cls.volume = cls.data["volume"] @classmethod def tearDownClass(cls): @@ -26,13 +33,15 @@ class TestCandle(TestCase): del cls.high del cls.low del cls.close - if hasattr(cls, "volume"): del cls.volume + if hasattr(cls, "volume"): + del cls.volume del cls.data + def setUp(self): + pass - def setUp(self): pass - def tearDown(self): pass - + def tearDown(self): + pass def test_ha(self): result = pandas_ta.ha(self.open, self.high, self.low, self.close) @@ -49,16 +58,23 @@ class TestCandle(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) def test_cdl_inside(self): - result = pandas_ta.cdl_inside(self.open, self.high, self.low, self.close) + result = pandas_ta.cdl_inside(self.open, self.high, self.low, + self.close) self.assertIsInstance(result, Series) self.assertEqual(result.name, "CDL_INSIDE") - result = pandas_ta.cdl_inside(self.open, self.high, self.low, self.close, asbool=True) + result = pandas_ta.cdl_inside(self.open, + self.high, + self.low, + self.close, + asbool=True) self.assertIsInstance(result, Series) - self.assertEqual(result.name, "CDL_INSIDE") \ No newline at end of file + self.assertEqual(result.name, "CDL_INSIDE") diff --git a/tests/test_indicator_momentum.py b/tests/test_indicator_momentum.py index a914360..a1b462b 100644 --- a/tests/test_indicator_momentum.py +++ b/tests/test_indicator_momentum.py @@ -1,4 +1,10 @@ -from .config import error_analysis, sample_data, CORRELATION, CORRELATION_THRESHOLD, VERBOSE +from .config import ( + error_analysis, + sample_data, + CORRELATION, + CORRELATION_THRESHOLD, + VERBOSE, +) from .context import pandas_ta from unittest import TestCase, skip @@ -8,8 +14,8 @@ from pandas import DataFrame, Series import talib as tal - class TestMomentum(TestCase): + @classmethod def setUpClass(cls): cls.data = sample_data @@ -18,7 +24,8 @@ class TestMomentum(TestCase): cls.high = cls.data["high"] cls.low = cls.data["low"] cls.close = cls.data["close"] - if "volume" in cls.data.columns: cls.volume = cls.data["volume"] + if "volume" in cls.data.columns: + cls.volume = cls.data["volume"] @classmethod def tearDownClass(cls): @@ -26,13 +33,15 @@ class TestMomentum(TestCase): del cls.high del cls.low del cls.close - if hasattr(cls, "volume"): del cls.volume + if hasattr(cls, "volume"): + del cls.volume del cls.data + def setUp(self): + pass - def setUp(self): pass - def tearDown(self): pass - + def tearDown(self): + pass def test_datetime_ordered(self): # Test if datetime64 index and ordered @@ -74,7 +83,9 @@ class TestMomentum(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -94,7 +105,9 @@ class TestMomentum(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -114,7 +127,9 @@ class TestMomentum(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -139,7 +154,9 @@ class TestMomentum(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -169,7 +186,10 @@ class TestMomentum(TestCase): self.assertIsInstance(result, Series) self.assertEqual(result.name, "INERTIA_20_14") - result = pandas_ta.inertia(self.close, self.high, self.low, refined=True) + result = pandas_ta.inertia(self.close, + self.high, + self.low, + refined=True) self.assertIsInstance(result, Series) self.assertEqual(result.name, "INERTIAr_20_14") @@ -177,7 +197,6 @@ class TestMomentum(TestCase): self.assertIsInstance(result, Series) self.assertEqual(result.name, "INERTIAt_20_14") - def test_kdj(self): result = pandas_ta.kdj(self.high, self.low, self.close) self.assertIsInstance(result, DataFrame) @@ -195,26 +214,39 @@ class TestMomentum(TestCase): try: expected = tal.MACD(self.close) - expecteddf = DataFrame({"MACD_12_26_9": expected[0], "MACDh_12_26_9": expected[2], "MACDs_12_26_9": expected[1]}) + expecteddf = DataFrame({ + "MACD_12_26_9": expected[0], + "MACDh_12_26_9": expected[2], + "MACDs_12_26_9": expected[1], + }) pdt.assert_frame_equal(result, expecteddf) except AssertionError as ae: try: - macd_corr = pandas_ta.utils.df_error_analysis(result.iloc[:,0], expecteddf.iloc[:,0], col=CORRELATION) + macd_corr = pandas_ta.utils.df_error_analysis( + result.iloc[:, 0], expecteddf.iloc[:, 0], col=CORRELATION) self.assertGreater(macd_corr, CORRELATION_THRESHOLD) except Exception as ex: - error_analysis(result.iloc[:,0], CORRELATION, ex) + error_analysis(result.iloc[:, 0], CORRELATION, ex) try: - history_corr = pandas_ta.utils.df_error_analysis(result.iloc[:,1], expecteddf.iloc[:,1], col=CORRELATION) + history_corr = pandas_ta.utils.df_error_analysis( + result.iloc[:, 1], expecteddf.iloc[:, 1], col=CORRELATION) self.assertGreater(history_corr, CORRELATION_THRESHOLD) except Exception as ex: - error_analysis(result.iloc[:,1], CORRELATION, ex, newline=False) + error_analysis(result.iloc[:, 1], + CORRELATION, + ex, + newline=False) try: - signal_corr = pandas_ta.utils.df_error_analysis(result.iloc[:,2], expecteddf.iloc[:,2], col=CORRELATION) + signal_corr = pandas_ta.utils.df_error_analysis( + result.iloc[:, 2], expecteddf.iloc[:, 2], col=CORRELATION) self.assertGreater(signal_corr, CORRELATION_THRESHOLD) except Exception as ex: - error_analysis(result.iloc[:,2], CORRELATION, ex, newline=False) + error_analysis(result.iloc[:, 2], + CORRELATION, + ex, + newline=False) def test_mom(self): result = pandas_ta.mom(self.close) @@ -226,7 +258,9 @@ class TestMomentum(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -243,10 +277,14 @@ class TestMomentum(TestCase): try: expected = tal.PPO(self.close) - pdt.assert_series_equal(result["PPO_12_26_9"], expected, check_names=False) + pdt.assert_series_equal(result["PPO_12_26_9"], + expected, + check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result["PPO_12_26_9"], expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result["PPO_12_26_9"], + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result["PPO_12_26_9"], CORRELATION, ex) @@ -271,7 +309,9 @@ class TestMomentum(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -286,7 +326,9 @@ class TestMomentum(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -332,11 +374,18 @@ class TestMomentum(TestCase): self.assertIsInstance(result, DataFrame) self.assertEqual(result.name, "SQZhlr_20_2.0_20_1.5") - result = pandas_ta.squeeze(self.high, self.low, self.close, lazybear=True) + result = pandas_ta.squeeze(self.high, + self.low, + self.close, + lazybear=True) self.assertIsInstance(result, DataFrame) self.assertEqual(result.name, "SQZ_20_2.0_20_1.5_LB") - result = pandas_ta.squeeze(self.high, self.low, self.close, tr=False, lazybear=True) + result = pandas_ta.squeeze(self.high, + self.low, + self.close, + tr=False, + lazybear=True) self.assertIsInstance(result, DataFrame) self.assertEqual(result.name, "SQZhlr_20_2.0_20_1.5_LB") @@ -347,7 +396,6 @@ class TestMomentum(TestCase): self.assertIsInstance(result, DataFrame) self.assertEqual(result.name, "STOCH_14_3_3") - def test_stochrsi(self): # TV Correlation result = pandas_ta.stochrsi(self.close) @@ -374,7 +422,9 @@ class TestMomentum(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -389,7 +439,9 @@ class TestMomentum(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: - error_analysis(result, CORRELATION, ex) \ No newline at end of file + error_analysis(result, CORRELATION, ex) diff --git a/tests/test_indicator_overlap.py b/tests/test_indicator_overlap.py index dbbbfee..75b161c 100644 --- a/tests/test_indicator_overlap.py +++ b/tests/test_indicator_overlap.py @@ -1,4 +1,10 @@ -from .config import CORRELATION, CORRELATION_THRESHOLD, error_analysis, sample_data, VERBOSE +from .config import ( + CORRELATION, + CORRELATION_THRESHOLD, + error_analysis, + sample_data, + VERBOSE, +) from .context import pandas_ta from unittest import TestCase @@ -9,8 +15,8 @@ import pandas as pd import talib as tal - class TestOverlap(TestCase): + @classmethod def setUpClass(cls): cls.data = sample_data @@ -19,7 +25,8 @@ class TestOverlap(TestCase): cls.high = cls.data["high"] cls.low = cls.data["low"] cls.close = cls.data["close"] - if "volume" in cls.data.columns: cls.volume = cls.data["volume"] + if "volume" in cls.data.columns: + cls.volume = cls.data["volume"] @classmethod def tearDownClass(cls): @@ -27,14 +34,15 @@ class TestOverlap(TestCase): del cls.high del cls.low del cls.close - if hasattr(cls, "volume"): del cls.volume + if hasattr(cls, "volume"): + del cls.volume del cls.data + def setUp(self): + pass - - def setUp(self): pass - def tearDown(self): pass - + def tearDown(self): + pass def test_dema(self): result = pandas_ta.dema(self.close) @@ -46,7 +54,9 @@ class TestOverlap(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -61,7 +71,9 @@ class TestOverlap(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -91,7 +103,9 @@ class TestOverlap(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -123,7 +137,9 @@ class TestOverlap(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -138,7 +154,9 @@ class TestOverlap(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -153,7 +171,9 @@ class TestOverlap(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -173,7 +193,9 @@ class TestOverlap(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -188,7 +210,9 @@ class TestOverlap(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -203,7 +227,9 @@ class TestOverlap(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -238,7 +264,9 @@ class TestOverlap(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -263,7 +291,9 @@ class TestOverlap(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -278,7 +308,9 @@ class TestOverlap(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -293,7 +325,9 @@ class TestOverlap(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -318,7 +352,9 @@ class TestOverlap(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -333,7 +369,9 @@ class TestOverlap(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) diff --git a/tests/test_indicator_performance.py b/tests/test_indicator_performance.py index 13770df..3dcc3e8 100644 --- a/tests/test_indicator_performance.py +++ b/tests/test_indicator_performance.py @@ -5,13 +5,14 @@ from unittest import TestCase from pandas import Series - class TestPerformace(TestCase): + @classmethod def setUpClass(cls): cls.data = sample_data cls.close = cls.data["close"] - cls.islong = (cls.close > pandas_ta.sma(cls.close, length=8)).astype(int) + cls.islong = (cls.close > pandas_ta.sma(cls.close, + length=8)).astype(int) @classmethod def tearDownClass(cls): @@ -19,10 +20,11 @@ class TestPerformace(TestCase): del cls.close del cls.islong + def setUp(self): + pass - def setUp(self): pass - def tearDown(self): pass - + def tearDown(self): + pass def test_log_return(self): result = pandas_ta.log_return(self.close) @@ -44,25 +46,45 @@ class TestPerformace(TestCase): self.assertEqual(result.name, "CUMPCTRET_1") def test_log_trend_return(self): - result = pandas_ta.trend_return(self.close, self.islong, log=True, cumulative=False) + result = pandas_ta.trend_return(self.close, + self.islong, + log=True, + cumulative=False) self.assertEqual(result.name, "LTR") def test_cum_log_trend_return(self): - result = pandas_ta.trend_return(self.close, self.islong, log=True, cumulative=True) + result = pandas_ta.trend_return(self.close, + self.islong, + log=True, + cumulative=True) self.assertEqual(result.name, "CLTR") def test_variable_cum_log_trend_return(self): - result = pandas_ta.trend_return(self.close, self.islong, log=True, cumulative=True, variable=True) + result = pandas_ta.trend_return(self.close, + self.islong, + log=True, + cumulative=True, + variable=True) self.assertEqual(result.name, "CLTR") def test_pct_trend_return(self): - result = pandas_ta.trend_return(self.close, self.islong, log=False, cumulative=False) + result = pandas_ta.trend_return(self.close, + self.islong, + log=False, + cumulative=False) self.assertEqual(result.name, "PTR") def test_cum_pct_trend_return(self): - result = pandas_ta.trend_return(self.close, self.islong, log=False, cumulative=True) + result = pandas_ta.trend_return(self.close, + self.islong, + log=False, + cumulative=True) self.assertEqual(result.name, "CPTR") def test_variable_pct_log_trend_return(self): - result = pandas_ta.trend_return(self.close, self.islong, log=False, cumulative=True, variable=True) - self.assertEqual(result.name, "CPTR") \ No newline at end of file + result = pandas_ta.trend_return(self.close, + self.islong, + log=False, + cumulative=True, + variable=True) + self.assertEqual(result.name, "CPTR") diff --git a/tests/test_indicator_statistics.py b/tests/test_indicator_statistics.py index 5e58dce..75ee92c 100644 --- a/tests/test_indicator_statistics.py +++ b/tests/test_indicator_statistics.py @@ -1,4 +1,10 @@ -from .config import error_analysis, sample_data, CORRELATION, CORRELATION_THRESHOLD, VERBOSE +from .config import ( + error_analysis, + sample_data, + CORRELATION, + CORRELATION_THRESHOLD, + VERBOSE, +) from .context import pandas_ta from unittest import TestCase, skip @@ -8,8 +14,8 @@ from pandas import DataFrame, Series import talib as tal - class TestStatistics(TestCase): + @classmethod def setUpClass(cls): cls.data = sample_data @@ -18,7 +24,8 @@ class TestStatistics(TestCase): cls.high = cls.data["high"] cls.low = cls.data["low"] cls.close = cls.data["close"] - if "volume" in cls.data.columns: cls.volume = cls.data["volume"] + if "volume" in cls.data.columns: + cls.volume = cls.data["volume"] @classmethod def tearDownClass(cls): @@ -26,12 +33,15 @@ class TestStatistics(TestCase): del cls.high del cls.low del cls.close - if hasattr(cls, "volume"): del cls.volume + if hasattr(cls, "volume"): + del cls.volume del cls.data + def setUp(self): + pass - def setUp(self): pass - def tearDown(self): pass + def tearDown(self): + pass def test_entropy(self): result = pandas_ta.entropy(self.close) @@ -73,7 +83,9 @@ class TestStatistics(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -88,7 +100,9 @@ class TestStatistics(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -96,4 +110,4 @@ class TestStatistics(TestCase): def test_zscore(self): result = pandas_ta.zscore(self.close) self.assertIsInstance(result, Series) - self.assertEqual(result.name, "Z_30") \ No newline at end of file + self.assertEqual(result.name, "Z_30") diff --git a/tests/test_indicator_trend.py b/tests/test_indicator_trend.py index 7ee35da..faf6b34 100644 --- a/tests/test_indicator_trend.py +++ b/tests/test_indicator_trend.py @@ -1,4 +1,10 @@ -from .config import error_analysis, sample_data, CORRELATION, CORRELATION_THRESHOLD, VERBOSE +from .config import ( + error_analysis, + sample_data, + CORRELATION, + CORRELATION_THRESHOLD, + VERBOSE, +) from .context import pandas_ta from unittest import TestCase, skip @@ -8,8 +14,8 @@ from pandas import DataFrame, Series import talib as tal - class TestTrend(TestCase): + @classmethod def setUpClass(cls): cls.data = sample_data @@ -18,7 +24,8 @@ class TestTrend(TestCase): cls.high = cls.data["high"] cls.low = cls.data["low"] cls.close = cls.data["close"] - if "volume" in cls.data.columns: cls.volume = cls.data["volume"] + if "volume" in cls.data.columns: + cls.volume = cls.data["volume"] @classmethod def tearDownClass(cls): @@ -26,13 +33,15 @@ class TestTrend(TestCase): del cls.high del cls.low del cls.close - if hasattr(cls, "volume"): del cls.volume + if hasattr(cls, "volume"): + del cls.volume del cls.data + def setUp(self): + pass - def setUp(self): pass - def tearDown(self): pass - + def tearDown(self): + pass def test_adx(self): result = pandas_ta.adx(self.high, self.low, self.close) @@ -41,10 +50,12 @@ class TestTrend(TestCase): try: expected = tal.ADX(self.high, self.low, self.close) - pdt.assert_series_equal(result.iloc[:,0], expected) + pdt.assert_series_equal(result.iloc[:, 0], expected) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result.iloc[:,0], expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result.iloc[:, 0], + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -61,33 +72,44 @@ class TestTrend(TestCase): try: expected = tal.AROON(self.high, self.low) - expecteddf = DataFrame({"AROOND_14": expected[0], "AROONU_14": expected[1]}) + expecteddf = DataFrame({ + "AROOND_14": expected[0], + "AROONU_14": expected[1] + }) pdt.assert_frame_equal(result, expecteddf) except AssertionError as ae: try: - aroond_corr = pandas_ta.utils.df_error_analysis(result.iloc[:,0], expecteddf.iloc[:,0], col=CORRELATION) + aroond_corr = pandas_ta.utils.df_error_analysis( + result.iloc[:, 0], expecteddf.iloc[:, 0], col=CORRELATION) self.assertGreater(aroond_corr, CORRELATION_THRESHOLD) except Exception as ex: - error_analysis(result.iloc[:,0], CORRELATION, ex) + error_analysis(result.iloc[:, 0], CORRELATION, ex) try: - aroonu_corr = pandas_ta.utils.df_error_analysis(result.iloc[:,1], expecteddf.iloc[:,1], col=CORRELATION) + aroonu_corr = pandas_ta.utils.df_error_analysis( + result.iloc[:, 1], expecteddf.iloc[:, 1], col=CORRELATION) self.assertGreater(aroonu_corr, CORRELATION_THRESHOLD) except Exception as ex: - error_analysis(result.iloc[:,1], CORRELATION, ex, newline=False) + error_analysis(result.iloc[:, 1], + CORRELATION, + ex, + newline=False) def test_aroon_osc(self): result = pandas_ta.aroon(self.high, self.low) try: expected = tal.AROONOSC(self.high, self.low) - pdt.assert_series_equal(result.iloc[:,2], expected) + pdt.assert_series_equal(result.iloc[:, 2], expected) except AssertionError as ae: try: - aroond_corr = pandas_ta.utils.df_error_analysis(result.iloc[:,2], expected, col=CORRELATION) + aroond_corr = pandas_ta.utils.df_error_analysis(result.iloc[:, + 2], + expected, + col=CORRELATION) self.assertGreater(aroond_corr, CORRELATION_THRESHOLD) except Exception as ex: - error_analysis(result.iloc[:,0], CORRELATION, ex) + error_analysis(result.iloc[:, 0], CORRELATION, ex) def test_chop(self): result = pandas_ta.chop(self.high, self.low, self.close) @@ -143,7 +165,9 @@ class TestTrend(TestCase): pdt.assert_series_equal(psar, expected) except AssertionError as ae: try: - psar_corr = pandas_ta.utils.df_error_analysis(psar, expected, col=CORRELATION) + psar_corr = pandas_ta.utils.df_error_analysis(psar, + expected, + col=CORRELATION) self.assertGreater(psar_corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(psar, CORRELATION, ex) diff --git a/tests/test_indicator_volatility.py b/tests/test_indicator_volatility.py index 29f20f2..3706d25 100644 --- a/tests/test_indicator_volatility.py +++ b/tests/test_indicator_volatility.py @@ -1,4 +1,10 @@ -from .config import error_analysis, sample_data, CORRELATION, CORRELATION_THRESHOLD, VERBOSE +from .config import ( + error_analysis, + sample_data, + CORRELATION, + CORRELATION_THRESHOLD, + VERBOSE, +) from .context import pandas_ta from unittest import TestCase, skip @@ -8,8 +14,8 @@ from pandas import DataFrame, Series import talib as tal - class TestVolatility(TestCase): + @classmethod def setUpClass(cls): cls.data = sample_data @@ -18,7 +24,8 @@ class TestVolatility(TestCase): cls.high = cls.data["high"] cls.low = cls.data["low"] cls.close = cls.data["close"] - if "volume" in cls.data.columns: cls.volume = cls.data["volume"] + if "volume" in cls.data.columns: + cls.volume = cls.data["volume"] @classmethod def tearDownClass(cls): @@ -26,13 +33,15 @@ class TestVolatility(TestCase): del cls.high del cls.low del cls.close - if hasattr(cls, "volume"): del cls.volume + if hasattr(cls, "volume"): + del cls.volume del cls.data + def setUp(self): + pass - def setUp(self): pass - def tearDown(self): pass - + def tearDown(self): + pass def test_aberration(self): result = pandas_ta.aberration(self.high, self.low, self.close) @@ -54,7 +63,9 @@ class TestVolatility(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -66,37 +77,58 @@ class TestVolatility(TestCase): try: expected = tal.BBANDS(self.close) - expecteddf = DataFrame({"BBL_5_2.0": expected[0], "BBM_5_2.0": expected[1], "BBU_5_2.0": expected[2]}) + expecteddf = DataFrame({ + "BBL_5_2.0": expected[0], + "BBM_5_2.0": expected[1], + "BBU_5_2.0": expected[2], + }) pdt.assert_frame_equal(result, expecteddf) except AssertionError as ae: try: - bbl_corr = pandas_ta.utils.df_error_analysis(result.iloc[:,0], expecteddf.iloc[:,0], col=CORRELATION) + bbl_corr = pandas_ta.utils.df_error_analysis(result.iloc[:, 0], + expecteddf.iloc[:, + 0], + col=CORRELATION) self.assertGreater(bbl_corr, CORRELATION_THRESHOLD) except Exception as ex: - error_analysis(result.iloc[:,0], CORRELATION, ex) + error_analysis(result.iloc[:, 0], CORRELATION, ex) try: - bbm_corr = pandas_ta.utils.df_error_analysis(result.iloc[:,1], expecteddf.iloc[:,1], col=CORRELATION) + bbm_corr = pandas_ta.utils.df_error_analysis(result.iloc[:, 1], + expecteddf.iloc[:, + 1], + col=CORRELATION) self.assertGreater(bbm_corr, CORRELATION_THRESHOLD) except Exception as ex: - error_analysis(result.iloc[:,1], CORRELATION, ex, newline=False) + error_analysis(result.iloc[:, 1], + CORRELATION, + ex, + newline=False) try: - bbu_corr = pandas_ta.utils.df_error_analysis(result.iloc[:,2], expecteddf.iloc[:,2], col=CORRELATION) + bbu_corr = pandas_ta.utils.df_error_analysis(result.iloc[:, 2], + expecteddf.iloc[:, + 2], + col=CORRELATION) self.assertGreater(bbu_corr, CORRELATION_THRESHOLD) except Exception as ex: - error_analysis(result.iloc[:,2], CORRELATION, ex, newline=False) + error_analysis(result.iloc[:, 2], + CORRELATION, + ex, + newline=False) def test_donchian(self): result = pandas_ta.donchian(self.high, self.low) self.assertIsInstance(result, DataFrame) self.assertEqual(result.name, "DC_20_20") - result = pandas_ta.donchian(self.high, self.low, lower_length=20, upper_length=5) + result = pandas_ta.donchian(self.high, + self.low, + lower_length=20, + upper_length=5) self.assertIsInstance(result, DataFrame) self.assertEqual(result.name, "DC_20_5") - def test_kc(self): result = pandas_ta.kc(self.high, self.low, self.close) self.assertIsInstance(result, DataFrame) @@ -121,7 +153,9 @@ class TestVolatility(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -154,7 +188,9 @@ class TestVolatility(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -166,4 +202,4 @@ class TestVolatility(TestCase): result = pandas_ta.ui(self.close, everget=True) self.assertIsInstance(result, Series) - self.assertEqual(result.name, "UIe_14") \ No newline at end of file + self.assertEqual(result.name, "UIe_14") diff --git a/tests/test_indicator_volume.py b/tests/test_indicator_volume.py index 354f6da..44e9ad0 100644 --- a/tests/test_indicator_volume.py +++ b/tests/test_indicator_volume.py @@ -1,4 +1,10 @@ -from .config import error_analysis, sample_data, CORRELATION, CORRELATION_THRESHOLD, VERBOSE +from .config import ( + error_analysis, + sample_data, + CORRELATION, + CORRELATION_THRESHOLD, + VERBOSE, +) from .context import pandas_ta from unittest import TestCase, skip @@ -8,8 +14,8 @@ from pandas import DataFrame, Series import talib as tal - class TestVolume(TestCase): + @classmethod def setUpClass(cls): cls.data = sample_data @@ -18,7 +24,8 @@ class TestVolume(TestCase): cls.high = cls.data["high"] cls.low = cls.data["low"] cls.close = cls.data["close"] - if "volume" in cls.data.columns: cls.volume_ = cls.data["volume"] + if "volume" in cls.data.columns: + cls.volume_ = cls.data["volume"] @classmethod def tearDownClass(cls): @@ -26,13 +33,15 @@ class TestVolume(TestCase): del cls.high del cls.low del cls.close - if hasattr(cls, "volume"): del cls.volume_ + if hasattr(cls, "volume"): + del cls.volume_ del cls.data + def setUp(self): + pass - def setUp(self): pass - def tearDown(self): pass - + def tearDown(self): + pass def test_ad(self): result = pandas_ta.ad(self.high, self.low, self.close, self.volume_) @@ -44,13 +53,16 @@ class TestVolume(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) def test_ad_open(self): - result = pandas_ta.ad(self.high, self.low, self.close, self.volume_, self.open) + result = pandas_ta.ad(self.high, self.low, self.close, self.volume_, + self.open) self.assertIsInstance(result, Series) self.assertEqual(result.name, "ADo") @@ -64,7 +76,9 @@ class TestVolume(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -99,7 +113,9 @@ class TestVolume(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) @@ -119,7 +135,9 @@ class TestVolume(TestCase): pdt.assert_series_equal(result, expected, check_names=False) except AssertionError as ae: try: - corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION) + corr = pandas_ta.utils.df_error_analysis(result, + expected, + col=CORRELATION) self.assertGreater(corr, CORRELATION_THRESHOLD) except Exception as ex: error_analysis(result, CORRELATION, ex) diff --git a/tests/test_strategy.py b/tests/test_strategy.py index 53a01d8..fa5bae8 100644 --- a/tests/test_strategy.py +++ b/tests/test_strategy.py @@ -18,7 +18,9 @@ strategy_timed = False timed = True verbose = False + class TestStrategyMethods(TestCase): + @classmethod def setUpClass(cls): cls.data = sample_data @@ -30,26 +32,30 @@ class TestStrategyMethods(TestCase): cls.speed_test = cls.speed_test.T cls.speed_test.index.name = "Test" cls.speed_test.columns = ["Columns", "Seconds"] - if cumulative: cls.speed_test["Cum. Seconds"] = cls.speed_test["Seconds"].cumsum() - if speed_table: cls.speed_test.to_csv("tests/speed_test.csv") + if cumulative: + cls.speed_test["Cum. Seconds"] = cls.speed_test["Seconds"].cumsum() + if speed_table: + cls.speed_test.to_csv("tests/speed_test.csv") if timed: print(f"[i] Cores: {cls.data.ta.cores}") print(f"[i] Total Datapoints: {cls.data.shape[0]}") print(cls.speed_test) del cls.data - def setUp(self): self.added_cols = 0 self.category = "" self.init_cols = len(self.data.columns) self.time_diff = 0 self.result = None - if verbose: print() - if timed: self.stime = perf_counter() + if verbose: + print() + if timed: + self.stime = perf_counter() def tearDown(self): - if timed: self.time_diff = perf_counter() - self.stime + if timed: + self.time_diff = perf_counter() - self.stime self.added_cols = len(self.data.columns) - self.init_cols self.assertGreaterEqual(self.added_cols, 1) @@ -59,7 +65,6 @@ class TestStrategyMethods(TestCase): self.speed_test[self.category] = [self.added_cols, self.time_diff] - # @skip def test_all(self): self.category = "All" @@ -67,41 +72,70 @@ class TestStrategyMethods(TestCase): @skip def test_all_strategy(self): - self.data.ta.strategy(pandas_ta.AllStrategy, verbose=verbose, timed=strategy_timed) + self.data.ta.strategy(pandas_ta.AllStrategy, + verbose=verbose, + timed=strategy_timed) @skip def test_all_name_strategy(self): self.category = "All" - self.data.ta.strategy(self.category, verbose=verbose, timed=strategy_timed) + self.data.ta.strategy(self.category, + verbose=verbose, + timed=strategy_timed) # @skip def test_candles_category(self): self.category = "Candles" - self.data.ta.strategy(self.category, verbose=verbose, timed=strategy_timed) + self.data.ta.strategy(self.category, + verbose=verbose, + timed=strategy_timed) # @skip def test_common(self): self.category = "Common" - self.data.ta.strategy(pandas_ta.CommonStrategy, verbose=verbose, timed=strategy_timed) + self.data.ta.strategy(pandas_ta.CommonStrategy, + verbose=verbose, + timed=strategy_timed) # @skip def test_custom_a(self): self.category = "Custom A" momo_bands_sma_ta = [ - {"kind": "rsi"}, # 1 - {"kind": "macd"}, # 3 - {"kind": "sma", "length": 50}, # 1 - {"kind": "sma", "length": 200}, # 1 - {"kind": "bbands", "length": 20}, # 3 - {"kind": "log_return", "cumulative": True}, # 1 - {"kind": "ema", "close": "CUMLOGRET_1", "length": 5, "suffix": "CLR"} + { + "kind": "rsi" + }, # 1 + { + "kind": "macd" + }, # 3 + { + "kind": "sma", + "length": 50 + }, # 1 + { + "kind": "sma", + "length": 200 + }, # 1 + { + "kind": "bbands", + "length": 20 + }, # 3 + { + "kind": "log_return", + "cumulative": True + }, # 1 + { + "kind": "ema", + "close": "CUMLOGRET_1", + "length": 5, + "suffix": "CLR" + }, ] custom = pandas_ta.Strategy( - "Commons with Cumulative Log Return EMA Chain", # name - momo_bands_sma_ta, # ta - "Common indicators with specific lengths and a chained indicator" # description + "Commons with Cumulative Log Return EMA Chain", # name + momo_bands_sma_ta, # ta + "Common indicators with specific lengths and a chained indicator", # description ) self.data.ta.strategy(custom, verbose=verbose, timed=strategy_timed) @@ -110,26 +144,32 @@ class TestStrategyMethods(TestCase): self.category = "Custom B" custom_args_ta = [ - {"kind":"ema", "params": (5,)}, - {"kind":"fisher", "params": (13, 7)}, + { + "kind": "ema", + "params": (5,) + }, + { + "kind": "fisher", + "params": (13, 7) + }, ] custom = pandas_ta.Strategy( - "Custom Args Tuple", custom_args_ta, - "Allow for easy filling in indicator arguments by argument placement." + "Custom Args Tuple", + custom_args_ta, + "Allow for easy filling in indicator arguments by argument placement.", ) self.data.ta.strategy(custom, verbose=verbose, timed=strategy_timed) def test_custom_col_names_tuple(self): self.category = "Custom C" - custom_args_ta = [ - {"kind":"bbands", "col_names": ("LB", "MB", "UB")} - ] + custom_args_ta = [{"kind": "bbands", "col_names": ("LB", "MB", "UB")}] custom = pandas_ta.Strategy( - "Custom Col Numbers Tuple", custom_args_ta, - "Allow for easy renaming of resultant columns" + "Custom Col Numbers Tuple", + custom_args_ta, + "Allow for easy renaming of resultant columns", ) self.data.ta.strategy(custom, verbose=verbose, timed=strategy_timed) @@ -137,47 +177,60 @@ class TestStrategyMethods(TestCase): def test_custom_col_numbers_tuple(self): self.category = "Custom D" - custom_args_ta = [ - {"kind":"macd", "col_numbers": (1,)} - ] + custom_args_ta = [{"kind": "macd", "col_numbers": (1,)}] custom = pandas_ta.Strategy( - "Custom Col Numbers Tuple", custom_args_ta, - "Allow for easy selection of resultant columns" + "Custom Col Numbers Tuple", + custom_args_ta, + "Allow for easy selection of resultant columns", ) self.data.ta.strategy(custom, verbose=verbose, timed=strategy_timed) # @skip def test_momentum_category(self): self.category = "Momentum" - self.data.ta.strategy(self.category, verbose=verbose, timed=strategy_timed) + self.data.ta.strategy(self.category, + verbose=verbose, + timed=strategy_timed) # @skip def test_overlap_category(self): self.category = "Overlap" - self.data.ta.strategy(self.category, verbose=verbose, timed=strategy_timed) + self.data.ta.strategy(self.category, + verbose=verbose, + timed=strategy_timed) # @skip def test_performance_category(self): self.category = "Performance" - self.data.ta.strategy(self.category, verbose=verbose, timed=strategy_timed) + self.data.ta.strategy(self.category, + verbose=verbose, + timed=strategy_timed) # @skip def test_statistics_category(self): self.category = "Statistics" - self.data.ta.strategy(self.category, verbose=verbose, timed=strategy_timed) + self.data.ta.strategy(self.category, + verbose=verbose, + timed=strategy_timed) # @skip def test_trend_category(self): self.category = "Trend" - self.data.ta.strategy(self.category, verbose=verbose, timed=strategy_timed) + self.data.ta.strategy(self.category, + verbose=verbose, + timed=strategy_timed) # @skip def test_volatility_category(self): self.category = "Volatility" - self.data.ta.strategy(self.category, verbose=verbose, timed=strategy_timed) + self.data.ta.strategy(self.category, + verbose=verbose, + timed=strategy_timed) # @skip def test_volume_category(self): self.category = "Volume" - self.data.ta.strategy(self.category, verbose=verbose, timed=strategy_timed) \ No newline at end of file + self.data.ta.strategy(self.category, + verbose=verbose, + timed=strategy_timed) diff --git a/tests/test_utils.py b/tests/test_utils.py index 037a72e..3982ae0 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -16,7 +16,9 @@ data = { "crossed": [0, 1], } + class TestUtilities(TestCase): + @classmethod def setUpClass(cls): cls.data = sample_data @@ -52,22 +54,30 @@ class TestUtilities(TestCase): @skip def test__above_below(self): - result = self.utils._above_below(self.crosseddf["a"], self.crosseddf["zero"], above=True) + result = self.utils._above_below(self.crosseddf["a"], + self.crosseddf["zero"], + above=True) self.assertIsInstance(result, Series) self.assertEqual(result.name, "a_A_zero") npt.assert_array_equal(result, self.crosseddf["c"]) - result = self.utils._above_below(self.crosseddf["a"], self.crosseddf["zero"], above=False) + result = self.utils._above_below(self.crosseddf["a"], + self.crosseddf["zero"], + above=False) self.assertIsInstance(result, Series) self.assertEqual(result.name, "a_B_zero") npt.assert_array_equal(result, self.crosseddf["b"]) - result = self.utils._above_below(self.crosseddf["c"], self.crosseddf["zero"], above=True) + result = self.utils._above_below(self.crosseddf["c"], + self.crosseddf["zero"], + above=True) self.assertIsInstance(result, Series) self.assertEqual(result.name, "c_A_zero") npt.assert_array_equal(result, self.crosseddf["c"]) - result = self.utils._above_below(self.crosseddf["c"], self.crosseddf["zero"], above=False) + result = self.utils._above_below(self.crosseddf["c"], + self.crosseddf["zero"], + above=False) self.assertIsInstance(result, Series) self.assertEqual(result.name, "c_B_zero") npt.assert_array_equal(result, self.crosseddf["zero"]) @@ -89,7 +99,8 @@ class TestUtilities(TestCase): self.assertEqual(result.name, "a_A_0") npt.assert_array_equal(result, self.crosseddf["c"]) - result = self.utils.above_value(self.crosseddf["a"], self.crosseddf["zero"]) + result = self.utils.above_value(self.crosseddf["a"], + self.crosseddf["zero"]) self.assertIsNone(result) def test_below(self): @@ -109,7 +120,8 @@ class TestUtilities(TestCase): self.assertEqual(result.name, "a_B_0") npt.assert_array_equal(result, self.crosseddf["b"]) - result = self.utils.below_value(self.crosseddf["a"], self.crosseddf["zero"]) + result = self.utils.below_value(self.crosseddf["a"], + self.crosseddf["zero"]) self.assertIsNone(result) def test_combination(self): @@ -118,42 +130,69 @@ class TestUtilities(TestCase): self.assertEqual(self.utils.combination(), 1) self.assertEqual(self.utils.combination(r=-1), 1) - self.assertEqual(self.utils.combination(n=10, r=4, repetition=False), 210) - self.assertEqual(self.utils.combination(n=10, r=4, repetition=True), 715) - + self.assertEqual(self.utils.combination(n=10, r=4, repetition=False), + 210) + self.assertEqual(self.utils.combination(n=10, r=4, repetition=True), + 715) + def test_cross_above(self): result = self.utils.cross(self.crosseddf["a"], self.crosseddf["b"]) self.assertIsInstance(result, Series) npt.assert_array_equal(result, self.crosseddf["crossed"]) - result = self.utils.cross(self.crosseddf["a"], self.crosseddf["b"], above=True) + result = self.utils.cross(self.crosseddf["a"], + self.crosseddf["b"], + above=True) self.assertIsInstance(result, Series) npt.assert_array_equal(result, self.crosseddf["crossed"]) def test_cross_below(self): - result = self.utils.cross(self.crosseddf["b"], self.crosseddf["a"], above=False) + result = self.utils.cross(self.crosseddf["b"], + self.crosseddf["a"], + above=False) self.assertIsInstance(result, Series) npt.assert_array_equal(result, self.crosseddf["crossed"]) def test_fibonacci(self): - self.assertIs(type(self.utils.fibonacci(zero=True, weighted=False)), np.ndarray) + self.assertIs(type(self.utils.fibonacci(zero=True, weighted=False)), + np.ndarray) - npt.assert_array_equal(self.utils.fibonacci(zero=True), np.array([0, 1, 1])) - npt.assert_array_equal(self.utils.fibonacci(zero=False), np.array([1, 1])) + npt.assert_array_equal(self.utils.fibonacci(zero=True), + np.array([0, 1, 1])) + npt.assert_array_equal(self.utils.fibonacci(zero=False), + np.array([1, 1])) - npt.assert_array_equal(self.utils.fibonacci(n=0, zero=True, weighted=False), np.array([0])) - npt.assert_array_equal(self.utils.fibonacci(n=0, zero=False, weighted=False), np.array([1])) + npt.assert_array_equal( + self.utils.fibonacci(n=0, zero=True, weighted=False), np.array([0])) + npt.assert_array_equal( + self.utils.fibonacci(n=0, zero=False, weighted=False), + np.array([1])) - npt.assert_array_equal(self.utils.fibonacci(n=5, zero=True, weighted=False), np.array([0, 1, 1, 2, 3, 5])) - npt.assert_array_equal(self.utils.fibonacci(n=5, zero=False, weighted=False), np.array([1, 1, 2, 3, 5])) + npt.assert_array_equal( + self.utils.fibonacci(n=5, zero=True, weighted=False), + np.array([0, 1, 1, 2, 3, 5]), + ) + npt.assert_array_equal( + self.utils.fibonacci(n=5, zero=False, weighted=False), + np.array([1, 1, 2, 3, 5]), + ) def test_fibonacci_weighted(self): - self.assertIs(type(self.utils.fibonacci(zero=True, weighted=True)), np.ndarray) - npt.assert_array_equal(self.utils.fibonacci(n=0, zero=True, weighted=True), np.array([0])) - npt.assert_array_equal(self.utils.fibonacci(n=0, zero=False, weighted=True), np.array([1])) + self.assertIs(type(self.utils.fibonacci(zero=True, weighted=True)), + np.ndarray) + npt.assert_array_equal( + self.utils.fibonacci(n=0, zero=True, weighted=True), np.array([0])) + npt.assert_array_equal( + self.utils.fibonacci(n=0, zero=False, weighted=True), np.array([1])) - npt.assert_allclose(self.utils.fibonacci(n=5, zero=True, weighted=True), np.array([0, 1/12, 1/12, 1/6, 1/4, 5/12])) - npt.assert_allclose(self.utils.fibonacci(n=5, zero=False, weighted=True), np.array([1/12, 1/12, 1/6, 1/4, 5/12])) + npt.assert_allclose( + self.utils.fibonacci(n=5, zero=True, weighted=True), + np.array([0, 1 / 12, 1 / 12, 1 / 6, 1 / 4, 5 / 12]), + ) + npt.assert_allclose( + self.utils.fibonacci(n=5, zero=False, weighted=True), + np.array([1 / 12, 1 / 12, 1 / 6, 1 / 4, 5 / 12]), + ) def test_get_time(self): result = self.utils.get_time() @@ -179,33 +218,49 @@ class TestUtilities(TestCase): array_1 = np.array([1]) npt.assert_array_equal(self.utils.pascals_triangle(), array_1) - npt.assert_array_equal(self.utils.pascals_triangle(weighted=True), array_1) - npt.assert_array_equal(self.utils.pascals_triangle(weighted=True, inverse=True), np.array([0])) + npt.assert_array_equal(self.utils.pascals_triangle(weighted=True), + array_1) + npt.assert_array_equal( + self.utils.pascals_triangle(weighted=True, inverse=True), + np.array([0])) - array_5 = self.utils.pascals_triangle(n=5) #or np.array([1, 5, 10, 10, 5, 1]) + array_5 = self.utils.pascals_triangle( + n=5) # or np.array([1, 5, 10, 10, 5, 1]) array_5w = array_5 / np.sum(array_5) array_5iw = 1 - array_5w npt.assert_array_equal(self.utils.pascals_triangle(n=-5), array_5) - npt.assert_array_equal(self.utils.pascals_triangle(n=-5, weighted=True), array_5w) - npt.assert_array_equal(self.utils.pascals_triangle(n=-5, weighted=True, inverse=True), array_5iw) + npt.assert_array_equal(self.utils.pascals_triangle(n=-5, weighted=True), + array_5w) + npt.assert_array_equal( + self.utils.pascals_triangle(n=-5, weighted=True, inverse=True), + array_5iw) npt.assert_array_equal(self.utils.pascals_triangle(n=5), array_5) - npt.assert_array_equal(self.utils.pascals_triangle(n=5, weighted=True), array_5w) - npt.assert_array_equal(self.utils.pascals_triangle(n=5, weighted=True, inverse=True), array_5iw) + npt.assert_array_equal(self.utils.pascals_triangle(n=5, weighted=True), + array_5w) + npt.assert_array_equal( + self.utils.pascals_triangle(n=5, weighted=True, inverse=True), + array_5iw) def test_symmetric_triangle(self): - npt.assert_array_equal(self.utils.symmetric_triangle(), np.array([1, 1])) - npt.assert_array_equal(self.utils.symmetric_triangle(weighted=True), np.array([0.5, 0.5])) + npt.assert_array_equal(self.utils.symmetric_triangle(), np.array([1, + 1])) + npt.assert_array_equal(self.utils.symmetric_triangle(weighted=True), + np.array([0.5, 0.5])) - array_4 = self.utils.symmetric_triangle(n=4) #or np.array([1, 2, 2, 1]) + array_4 = self.utils.symmetric_triangle( + n=4) # or np.array([1, 2, 2, 1]) array_4w = array_4 / np.sum(array_4) npt.assert_array_equal(self.utils.symmetric_triangle(n=4), array_4) - npt.assert_array_equal(self.utils.symmetric_triangle(n=4, weighted=True), array_4w) + npt.assert_array_equal( + self.utils.symmetric_triangle(n=4, weighted=True), array_4w) - array_5 = self.utils.symmetric_triangle(n=5) #or np.array([1, 2, 3, 2, 1]) + array_5 = self.utils.symmetric_triangle( + n=5) # or np.array([1, 2, 3, 2, 1]) array_5w = array_5 / np.sum(array_5) npt.assert_array_equal(self.utils.symmetric_triangle(n=5), array_5) - npt.assert_array_equal(self.utils.symmetric_triangle(n=5, weighted=True), array_5w) + npt.assert_array_equal( + self.utils.symmetric_triangle(n=5, weighted=True), array_5w) def test_zero(self): self.assertEqual(self.utils.zero(-0.0000000000000001), 0) @@ -231,4 +286,4 @@ class TestUtilities(TestCase): self.assertEqual(self.utils.get_offset(0), 0) self.assertEqual(self.utils.get_offset(-1.1), 0) - self.assertEqual(self.utils.get_offset(1), 1) \ No newline at end of file + self.assertEqual(self.utils.get_offset(1), 1)