diff --git a/.gitignore b/.gitignore
index 5d129902..dc05d781 100644
--- a/.gitignore
+++ b/.gitignore
@@ -131,7 +131,6 @@ AlphaVantageAPI/
# Data & NB Exclusions
*.csv
-jnb/*.ipynb
data/datas.csv
data/f500.csv
data/GLD_D_tv.csv
@@ -142,4 +141,6 @@ data/SPY_D_TV2.csv
data/SPY_D_TV3.csv
data/TV_5min.csv
data/tulip.csv
-examples/*.csv
\ No newline at end of file
+examples/*.csv
+jnb/*.ipynb
+jnb/*.txt
\ No newline at end of file
diff --git a/README.md b/README.md
index 0bfd4544..fe3e28b7 100644
--- a/README.md
+++ b/README.md
@@ -14,10 +14,11 @@ Pandas TA - A Technical Analysis Library in Python 3
[![Downloads](https://img.shields.io/pypi/dm/pandas_ta?style=flat)](https://pypistats.org/packages/pandas_ta)
[![Stars](https://img.shields.io/github/stars/twopirllc/pandas-ta?style=flat)](#stars)
[![Forks](https://img.shields.io/github/forks/twopirllc/pandas-ta?style=flat)](#forks)
-[![Used By](https://img.shields.io/badge/used_by-146-orange.svg?style=flat)](#usedby)
+[![Used By](https://img.shields.io/badge/used_by-170-orange.svg?style=flat)](#usedby)
[![Contributors](https://img.shields.io/github/contributors/twopirllc/pandas-ta?style=flat)](#contributors)
[![Issues](https://img.shields.io/github/issues-raw/twopirllc/pandas-ta?style=flat)](#issues)
[![Closed Issues](https://img.shields.io/github/issues-closed-raw/twopirllc/pandas-ta?style=flat)](#closed-issues)
+[![Buy Me a Coffee](https://img.shields.io/badge/buy_me_a_coffee-orange.svg?style=flat)](https://www.buymeacoffee.com/twopirllc)
@@ -55,7 +56,7 @@ _Pandas Technical Analysis_ (**Pandas TA**) is an easy to use library that lever
* [Candles](#candles-64)
* [Cycles](#cycles-1)
* [Momentum](#momentum-41)
- * [Overlap](#overlap-32)
+ * [Overlap](#overlap-33)
* [Performance](#performance-3)
* [Statistics](#statistics-11)
* [Trend](#trend-18)
@@ -68,11 +69,10 @@ _Pandas Technical Analysis_ (**Pandas TA**) is an easy to use library that lever
* [Breaking Indicators](#breaking-indicators)
* [New Indicators](#new-indicators)
* [Updated Indicators](#updated-indicators)
+* [Sources](#sources)
+* [Support](#support)
-
-
-
@@ -80,21 +80,23 @@ _Pandas Technical Analysis_ (**Pandas TA**) is an easy to use library that lever
* Has 130+ indicators and utility functions.
* **BETA** Also Pandas TA will run TA Lib's version, this includes TA Lib's 63 Chart Patterns.
-* Indicators are tightly correlated with the de facto [TA Lib](https://github.com/mrjbq7/ta-lib) if they share common indicators.
+* Indicators in Python are tightly correlated with the _de facto_ [TA Lib](https://github.com/mrjbq7/ta-lib) if they share common indicators.
+* If TA Lib is also installed, TA Lib computations are enabled by default but can be disabled disabled per indicator by using the argument ```talib=False```.
+ * For instance to disable TA Lib calculation for **stdev**: ```ta.stdev(df["close"], length=30, talib=False)```.
+* **NEW**! Include External Custom Indicators independent of the builtin Pandas TA indicators. For more information, see ```import_dir``` documentation under ```/pandas_ta/custom.py```.
* Example Jupyter Notebook with **vectorbt** Portfolio Backtesting with Pandas TA's ```ta.tsignals``` method.
* Have the need for speed? By using the DataFrame _strategy_ method, you get **multiprocessing** for free! __Conditions permitting__.
* Easily add _prefixes_ or _suffixes_ or _both_ to columns names. Useful for Custom Chained Strategies.
* Example Jupyter Notebooks under the [examples](https://github.com/twopirllc/pandas-ta/tree/main/examples) directory, including how to create Custom Strategies using the new [__Strategy__ Class](https://github.com/twopirllc/pandas-ta/tree/main/examples/PandaTA_Strategy_Examples.ipynb)
-* Potential Data Leaks: **ichimoku** and **dpo**. See indicator list below for details.
+* Potential Data Leaks: **dpo** and **ichimoku**. See indicator list below for details. Set ```lookahead=False``` to disable.
**Under Development**
===================
-**Pandas TA** checks if the user has some common trading packages installed including but not limited to: [**TA Lib**](https://mrjbq7.github.io/ta-lib/), [**Vector BT**](https://github.com/polakowo/vectorbt), [**YFinance**](https://github.com/ranaroussi/yfinance) ... Much of which is experimental and likely to break until it stabilizes more.
+**Pandas TA** checks if the user has some common trading packages installed including but not limited to: [**TA Lib**](https://mrjbq7.github.io/ta-lib/), [**Vector BT**](https://github.com/polakowo/vectorbt), [**YFinance**](https://github.com/ranaroussi/yfinance) ... Much of which is _experimental_ and likely to break until it stabilizes more.
* If **TA Lib** installed, existing indicators will _eventually_ get a **TA Lib** version.
* Easy Downloading of _ohlcv_ data using [yfinance](https://github.com/ranaroussi/yfinance). See ```help(ta.ticker)``` and ```help(ta.yf)``` and examples below.
-* Hopefully soon a Pandas TA _YAML_ configuration file contained in ```~/pandas_ta/``` can be implemented. To see the proposed specification and leave comments and suggestions on it's implementation, see Issue [#258](https://github.com/twopirllc/pandas-ta/issues/258).
* Some Common Performance Metrics
@@ -104,14 +106,14 @@ _Pandas Technical Analysis_ (**Pandas TA**) is an easy to use library that lever
Stable
------
-The ```pip``` version is the last stable release. Version: *0.3.02b*
+The ```pip``` version is the last stable release. Version: *0.3.14b*
```sh
$ pip install pandas_ta
```
Latest Version
--------------
-Best choice! Version: *0.3.02b*
+Best choice! Version: *0.3.14b*
* Includes all fixes and updates between **pypi** and what is covered in this README.
```sh
$ pip install -U git+https://github.com/twopirllc/pandas-ta
@@ -158,6 +160,8 @@ df.tail()
# **Help**
+**Some** indicator arguments have been reordered for consistency. Use ```help(ta.indicator_name)``` for more information or make a Pull Request to improve documentation.
+
```python
import pandas as pd
import pandas_ta as ta
@@ -208,9 +212,9 @@ Thanks for using **Pandas TA**!
**Contributors**
================
-_Thank you for your contributions!_
+_Thank you for your contributions!_
-[AbyssAlora](https://github.com/AbyssAlora) | [alexonab](https://github.com/alexonab) | [allahyarzadeh](https://github.com/allahyarzadeh) | [bizso09](https://github.com/bizso09) | [CMobley7](https://github.com/CMobley7) | [codesutras](https://github.com/codesutras) | [DannyMartens](https://github.com/DannyMartens) | [DrPaprikaa](https://github.com/DrPaprikaa) | [daikts](https://github.com/daikts) | [delicateear](https://github.com/delicateear) | [dorren](https://github.com/dorren) | [edwardwang1](https://github.com/edwardwang1) | [FGU1](https://github.com/FGU1) | [ffhirata](https://github.com/ffhirata) | [floatinghotpot](https://github.com/floatinghotpot) | [GSlinger](https://github.com/gslinger) | [JoeSchr](https://github.com/JoeSchr) | [lluissalord](https://github.com/lluissalord) | [luisbarrancos](https://github.com/luisbarrancos) | [M6stafa](https://github.com/M6stafa) | [maxdignan](https://github.com/maxdignan) | [mchant](https://github.com/mchant) | [moritzgun](https://github.com/moritzgun) | [NkosenhleDuma](https://github.com/NkosenhleDuma) | [nicoloridulfo](https://github.com/nicoloridulfo) | [pbrumblay](https://github.com/pbrumblay) | [RajeshDhalange](https://github.com/RajeshDhalange) | [rengel8](https://github.com/rengel8) | [rluong003](https://github.com/rluong003) | [SoftDevDanial](https://github.com/SoftDevDanial) | [tg12](https://github.com/tg12) | [twrobel](https://github.com/twrobel) | [WellMaybeItIs](https://github.com/WellMaybeItIs) | [whubsch](https://github.com/whubsch) | [witokondoria](https://github.com/witokondoria) | [wouldayajustlookatit](https://github.com/wouldayajustlookatit) | [YuvalWein](https://github.com/YuvalWein) | [zlpatel](https://github.com/zlpatel)
+
@@ -719,7 +723,7 @@ df = df.ta.cdl_pattern(name=["doji", "inside"])
-### **Overlap** (32)
+### **Overlap** (33)
* _Arnaud Legoux Moving Average_: **alma**
* _Double Exponential Moving Average_: **dema**
@@ -733,7 +737,8 @@ df = df.ta.cdl_pattern(name=["doji", "inside"])
* _Holt-Winter Moving Average_: **hwma**
* _Ichimoku Kinkō Hyō_: **ichimoku**
* Returns two DataFrames. For more information: ```help(ta.ichimoku)```.
- * Drop the Chikou Span Column, the final column of the first resultant DataFrame, remove potential data leak.
+ * ```lookahead=False``` drops the Chikou Span Column to prevent potential data leak.
+* _Jurik Moving Average_: **jma**
* _Kaufman's Adaptive Moving Average_: **kama**
* _Linear Regression_: **linreg**
* _McGinley Dynamic_: **mcgd**
@@ -807,7 +812,7 @@ Use parameter: cumulative=**True** for cumulative results.
* Formally: **linear_decay**
* _Decreasing_: **decreasing**
* _Detrended Price Oscillator_: **dpo**
- * Set ```centered=False``` to remove potential data leak.
+ * Set ```lookahead=False``` to disable centering and remove potential data leak.
* _Increasing_: **increasing**
* _Long Run_: **long_run**
* _Parabolic Stop and Reverse_: **psar**
@@ -964,6 +969,7 @@ trading account, or fund. See ```help(ta.drawdown)```
* _Cross Signals_ (**xsignals**) was created by Kevin Johnson. It is a wrapper of Trade Signals that returns Trends, Trades, Entries and Exits. Cross Signals are commonly used for **bbands**, **rsi**, **zscore** crossing some value either above or below two values at different times. See ```help(ta.xsignals)```
* _Directional Movement_ (**dm**) developed by J. Welles Wilder in 1978 attempts to determine which direction the price of an asset is moving. See ```help(ta.dm)```
* _Even Better Sinewave_ (**ebsw**) measures market cycles and uses a low pass filter to remove noise. See: ```help(ta.ebsw)```
+* _Jurik Moving Average_ (**jma**) attempts to eliminate noise to see the "true" underlying activity.. See: ```help(ta.jma)```
* _Klinger Volume Oscillator_ (**kvo**) was developed by Stephen J. Klinger. It is designed to predict price reversals in a market by comparing volume to price.. See ```help(ta.kvo)```
* _Schaff Trend Cycle_ (**stc**) is an evolution of the popular MACD incorportating two cascaded stochastic calculations with additional smoothing. See ```help(ta.stc)```
* _Squeeze Pro_ (**squeeze_pro**) is an extended version of "TTM Squeeze" from John Carter. See ```help(ta.squeeze_pro)```
@@ -976,22 +982,40 @@ of the last bars defined by the length parameter. See ```help(ta.tos_stdevall)``
## **Updated Indicators**
+
+* _Acceleration Bands_ (**accbands**) Argument ```mamode``` renamed to ```mode```. See ```help(ta.accbands)```.
* _ADX_ (**adx**): Added ```mamode``` with default "**RMA**" and with the same ```mamode``` options as TradingView. New argument ```lensig``` so it behaves like TradingView's builtin ADX indicator. See ```help(ta.adx)```.
* _Archer Moving Averages Trends_ (**amat**): Added ```drift``` argument and more descriptive column names.
* _Average True Range_ (**atr**): The default ```mamode``` is now "**RMA**" and with the same ```mamode``` options as TradingView. See ```help(ta.atr)```.
* _Bollinger Bands_ (**bbands**): New argument ```ddoff``` to control the Degrees of Freedom. Also included BB Percent (BBP) as the final column. Default is 0. See ```help(ta.bbands)```.
* _Choppiness Index_ (**chop**): New argument ```ln``` to use Natural Logarithm (True) instead of the Standard Logarithm (False). Default is False. See ```help(ta.chop)```.
* _Chande Kroll Stop_ (**cksp**): Added ```tvmode``` with default ```True```. When ```tvmode=False```, **cksp** implements “The New Technical Trader” with default values. See ```help(ta.cksp)```.
+* _Chande Momentum Oscillator_ (**cmo**): New argument ```talib``` will use TA Lib's version and if TA Lib is installed. Default is True. See ```help(ta.cmo)```.
* _Decreasing_ (**decreasing**): New argument ```strict``` checks if the series is continuously decreasing over period ```length``` with a faster calculation. Default: ```False```. The ```percent``` argument has also been added with default None. See ```help(ta.decreasing)```.
* _Increasing_ (**increasing**): New argument ```strict``` checks if the series is continuously increasing over period ```length``` with a faster calculation. Default: ```False```. The ```percent``` argument has also been added with default None. See ```help(ta.increasing)```.
+* _Klinger Volume Oscillator_ (**kvo**): Implements TradingView's Klinger Volume Oscillator version. See ```help(ta.kvo)```.
+* _Linear Regression_ (**linreg**): Checks **numpy**'s version to determine whether to utilize the ```as_strided``` method or the newer ```sliding_window_view``` method. This should resolve Issues with Google Colab and it's delayed dependency updates as well as TensorFlow's dependencies as discussed in Issues [#285](https://github.com/twopirllc/pandas-ta/issues/285) and [#329](https://github.com/twopirllc/pandas-ta/issues/329).
+* _Moving Average Convergence Divergence_ (**macd**): New argument ```asmode``` enables AS version of MACD. Default is False. See ```help(ta.macd)```.
* _Parabolic Stop and Reverse_ (**psar**): Bug fix and adjustment to match TradingView's ```sar```. New argument ```af0``` to initialize the Acceleration Factor. See ```help(ta.psar)```.
* _Percentage Price Oscillator_ (**ppo**): Included new argument ```mamode``` as an option. Default is **sma** to match TA Lib. See ```help(ta.ppo)```.
+* _True Strength Index_ (**tsi**): Added ```signal``` with default ```13``` and Signal MA Mode ```mamode``` with default **ema** as arguments. See ```help(ta.tsi)```.
* _Volume Profile_ (**vp**): Calculation improvements. See [Pull Request #320](https://github.com/twopirllc/pandas-ta/pull/320) See ```help(ta.vp)```.
* _Volume Weighted Moving Average_ (**vwma**): Fixed bug in DataFrame Extension call. See ```help(ta.vwma)```.
* _Volume Weighted Average Price_ (**vwap**): Added a new parameter called ```anchor```. Default: "D" for "Daily". See [Timeseries Offset Aliases](https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#timeseries-offset-aliases) for additional options. **Requires** the DataFrame index to be a DatetimeIndex. See ```help(ta.vwap)```.
+* _Volume Weighted Moving Average_ (**vwma**): Fixed bug in DataFrame Extension call. See ```help(ta.vwma)```.
* _Z Score_ (**zscore**): Changed return column name from ```Z_length``` to ```ZS_length```. See ```help(ta.zscore)```.
# **Sources**
[Original TA-LIB](http://ta-lib.org/) | [TradingView](http://www.tradingview.com) | [Sierra Chart](https://search.sierrachart.com/?Query=indicators&submitted=true) | [MQL5](https://www.mql5.com) | [FM Labs](https://www.fmlabs.com/reference/default.htm) | [Pro Real Code](https://www.prorealcode.com/prorealtime-indicators) | [User 42](https://user42.tuxfamily.org/chart/manual/index.html)
+
+
+
+# **Support**
+
+Feeling generous, like the package or want to see it become more a mature package?
+
+### Consider
+[!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/twopirllc)
+
diff --git a/examples/ni.py b/examples/ni.py
new file mode 100644
index 00000000..41aedc0c
--- /dev/null
+++ b/examples/ni.py
@@ -0,0 +1,79 @@
+# -*- coding: utf-8 -*-
+from pandas_ta.overlap import sma
+from pandas_ta.utils import get_offset, verify_series
+
+# - Standard definition of your custom indicator function (including docs)-
+
+def ni(close, length=None, centered=False, offset=None, **kwargs):
+ """
+ Example indicator ni
+ """
+ # Validate Arguments
+ length = int(length) if length and length > 0 else 20
+ close = verify_series(close, length)
+ offset = get_offset(offset)
+
+ if close is None: return
+
+ # Calculate Result
+ t = int(0.5 * length) + 1
+ ma = sma(close, length)
+
+ ni = close - ma.shift(t)
+ if centered:
+ ni = (close.shift(t) - ma).shift(-t)
+
+ # Offset
+ if offset != 0:
+ ni = ni.shift(offset)
+
+ # Handle fills
+ if "fillna" in kwargs:
+ ni.fillna(kwargs["fillna"], inplace=True)
+ if "fill_method" in kwargs:
+ ni.fillna(method=kwargs["fill_method"], inplace=True)
+
+ # Name and Categorize it
+ ni.name = f"ni_{length}"
+ ni.category = "trend"
+
+ return ni
+
+ni.__doc__ = \
+"""Example indicator (NI)
+
+Is an indicator provided solely as an example
+
+Sources:
+ https://github.com/twopirllc/pandas-ta/issues/264
+
+Calculation:
+ Default Inputs:
+ length=20, centered=False
+ SMA = Simple Moving Average
+ t = int(0.5 * length) + 1
+
+ ni = close.shift(t) - SMA(close, length)
+ if centered:
+ ni = ni.shift(-t)
+
+Args:
+ close (pd.Series): Series of 'close's
+ length (int): It's period. Default: 20
+ centered (bool): Shift the ni back by int(0.5 * length) + 1. Default: False
+ offset (int): How many periods to offset the result. Default: 0
+
+Kwargs:
+ fillna (value, optional): pd.DataFrame.fillna(value)
+ fill_method (value, optional): Type of fill method
+
+Returns:
+ pd.Series: New feature generated.
+"""
+
+# - Define a matching class method --------------------------------------------
+
+def ni_method(self, length=None, offset=None, **kwargs):
+ close = self._get_column(kwargs.pop("close", "close"))
+ result = ni(close=close, length=length, offset=offset, **kwargs)
+ return self._post_process(result, **kwargs)
\ No newline at end of file
diff --git a/pandas_ta/__init__.py b/pandas_ta/__init__.py
index d3a5d317..0e740b84 100644
--- a/pandas_ta/__init__.py
+++ b/pandas_ta/__init__.py
@@ -55,9 +55,9 @@
# Overlap
"overlap": [
"alma", "dema", "ema", "fwma", "hilo", "hl2", "hlc3", "hma", "ichimoku",
- "kama", "linreg", "mcgd", "midpoint", "midprice", "ohlc4", "pwma", "rma",
- "sinwma", "sma", "ssf", "supertrend", "swma", "t3", "tema", "trima",
- "vidya", "vwap", "vwma", "wcp", "wma", "zlma"
+ "jma", "kama", "linreg", "mcgd", "midpoint", "midprice", "ohlc4",
+ "pwma", "rma", "sinwma", "sma", "ssf", "supertrend", "swma", "t3",
+ "tema", "trima", "vidya", "vwap", "vwma", "wcp", "wma", "zlma"
],
# Performance
"performance": ["log_return", "percent_return"],
diff --git a/pandas_ta/core.py b/pandas_ta/core.py
index 7eba78e6..fdee64ab 100644
--- a/pandas_ta/core.py
+++ b/pandas_ta/core.py
@@ -4,6 +4,7 @@
from pathlib import Path
from time import perf_counter
from typing import List, Tuple
+from warnings import simplefilter
import pandas as pd
from numpy import log10 as npLog10
@@ -250,15 +251,15 @@ class AnalysisIndicators(BasePandasObject):
_time_range = "years"
_last_run = get_time(_exchange, to_string=True)
- # def __init__(self, pandas_obj):
- # # self._validate(pandas_obj)
- # self._df = pandas_obj
- # self._last_run = get_time(self._exchange, to_string=True)
+ def __init__(self, pandas_obj):
+ self._validate(pandas_obj)
+ self._df = pandas_obj
+ self._last_run = get_time(self._exchange, to_string=True)
- # @staticmethod
- # def _validate(df: Tuple[pd.DataFrame, pd.Series]):
- # if isinstance(df, pd.Series) or isinstance(df, pd.DataFrame):
- # raise AttributeError("[X] Must be either a Pandas Series or DataFrame.")
+ @staticmethod
+ def _validate(obj: Tuple[pd.DataFrame, pd.Series]):
+ if not isinstance(obj, pd.DataFrame) and not isinstance(obj, pd.Series):
+ raise AttributeError("[X] Must be either a Pandas Series or DataFrame.")
# DataFrame Behavioral Methods
def __call__(
@@ -400,8 +401,9 @@ def _append(self, result=None, **kwargs) -> None:
df = self._df
if df is None or result is None: return
else:
+ simplefilter(action="ignore", category=pd.errors.PerformanceWarning)
if "col_names" in kwargs and not isinstance(kwargs["col_names"], tuple):
- kwargs["col_names"] = (kwargs["col_names"],)
+ kwargs["col_names"] = (kwargs["col_names"],) # Note: tuple(kwargs["col_names"]) doesn't work
if isinstance(result, pd.DataFrame):
# If specified in kwargs, rename the columns.
@@ -761,10 +763,10 @@ def strategy(self, *args, **kwargs):
else:
# Without multiprocessing:
if verbose:
+ _col_msg = f"[i] No mulitproccessing (cores = 0)."
if has_col_names:
- print(f"[i] No mulitproccessing support for 'col_names' option.")
- else:
- print(f"[i] No mulitproccessing (cores = 0).")
+ _col_msg = f"[i] No mulitproccessing support for 'col_names' option."
+ print(_col_msg)
if mode["custom"]:
if Imports["tqdm"] and verbose:
@@ -784,6 +786,7 @@ def strategy(self, *args, **kwargs):
else:
for ind in ta:
getattr(self, ind)(*tuple(), **kwargs)
+ self._last_run = get_time(self.exchange, to_string=True)
# Apply prefixes/suffixes and appends indicator results to the DataFrame
[self._post_process(r, **kwargs) for r in results]
@@ -900,9 +903,9 @@ def ao(self, fast=None, slow=None, offset=None, **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):
+ def apo(self, fast=None, slow=None, mamode=None, offset=None, **kwargs):
close = self._get_column(kwargs.pop("close", "close"))
- result = apo(close=close, fast=fast, slow=slow, offset=offset, **kwargs)
+ result = apo(close=close, fast=fast, slow=slow, mamode=mamode, offset=offset, **kwargs)
return self._post_process(result, **kwargs)
def bias(self, length=None, mamode=None, offset=None, **kwargs):
@@ -958,10 +961,10 @@ def cti(self, length=None, offset=None, **kwargs):
result = cti(close=close, length=length, offset=offset, **kwargs)
return self._post_process(result, **kwargs)
- def dm(self, drift=None, offset=None, **kwargs):
+ def dm(self, drift=None, offset=None, mamode=None, **kwargs):
high = self._get_column(kwargs.pop("high", "high"))
low = self._get_column(kwargs.pop("low", "low"))
- result = dm(high=high, low=low, drift=drift, offset=offset, **kwargs)
+ result = dm(high=high, low=low, drift=drift, mamode=mamode, offset=offset, **kwargs)
return self._post_process(result, **kwargs)
def er(self, length=None, drift=None, offset=None, **kwargs):
@@ -1078,18 +1081,18 @@ def smi(self, fast=None, slow=None, signal=None, scalar=None, offset=None, **kwa
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):
+ def squeeze(self, bb_length=None, bb_std=None, kc_length=None, kc_scalar=None, mom_length=None, mom_smooth=None, use_tr=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 = 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, mamode=mamode, offset=offset, **kwargs)
return self._post_process(result, **kwargs)
- def squeeze_pro(self, bb_length=None, bb_std=None, kc_length=None, kc_scalar_wide=None, kc_scalar_normal=None, kc_scalar_narrow=None, mom_length=None, mom_smooth=None, use_tr=None, offset=None, **kwargs):
+ def squeeze_pro(self, bb_length=None, bb_std=None, kc_length=None, kc_scalar_wide=None, kc_scalar_normal=None, kc_scalar_narrow=None, mom_length=None, mom_smooth=None, use_tr=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 = squeeze_pro(high=high, low=low, close=close, bb_length=bb_length, bb_std=bb_std, kc_length=kc_length, kc_scalar_wide=kc_scalar_wide, kc_scalar_normal=kc_scalar_normal, kc_scalar_narrow=kc_scalar_narrow, mom_length=mom_length, mom_smooth=mom_smooth, use_tr=use_tr, offset=offset, **kwargs)
+ result = squeeze_pro(high=high, low=low, close=close, bb_length=bb_length, bb_std=bb_std, kc_length=kc_length, kc_scalar_wide=kc_scalar_wide, kc_scalar_normal=kc_scalar_normal, kc_scalar_narrow=kc_scalar_narrow, mom_length=mom_length, mom_smooth=mom_smooth, use_tr=use_tr, mamode=mamode, offset=offset, **kwargs)
return self._post_process(result, **kwargs)
def stc(self, ma1=None, ma2=None, osc=None, tclength=None, fast=None, slow=None, factor=None, offset=None, **kwargs):
@@ -1097,18 +1100,18 @@ def stc(self, ma1=None, ma2=None, osc=None, tclength=None, fast=None, slow=None,
result = stc(close=close, ma1=ma1, ma2=ma2, osc=osc, tclength=tclength, fast=fast, slow=slow, factor=factor, offset=offset, **kwargs)
return self._post_process(result, **kwargs)
- def stoch(self, fast_k=None, slow_k=None, slow_d=None, offset=None, **kwargs):
+ def stoch(self, fast_k=None, slow_k=None, slow_d=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 = 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, mamode=mamode, offset=offset, **kwargs)
return self._post_process(result, **kwargs)
- def stochrsi(self, length=None, rsi_length=None, k=None, d=None, offset=None, **kwargs):
+ def stochrsi(self, length=None, rsi_length=None, k=None, d=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 = 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, mamode=mamode, offset=offset, **kwargs)
return self._post_process(result, **kwargs)
def td_seq(self, asint=None, offset=None, show_all=None, **kwargs):
@@ -1121,9 +1124,9 @@ def trix(self, length=None, signal=None, scalar=None, drift=None, offset=None, *
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):
+ def tsi(self, fast=None, slow=None, drift=None, mamode=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)
+ result = tsi(close=close, fast=fast, slow=slow, drift=drift, mamode=mamode, 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):
@@ -1191,16 +1194,21 @@ def hwma(self, na=None, nb=None, nc=None, offset=None, **kwargs):
result = hwma(close=close, na=na, nb=nb, nc=nc, offset=offset, **kwargs)
return self._post_process(result, **kwargs)
+ def jma(self, length=None, phase=None, offset=None, **kwargs):
+ close = self._get_column(kwargs.pop("close", "close"))
+ result = jma(close=close, length=length, phase=phase, 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)
return self._post_process(result, **kwargs)
- def ichimoku(self, tenkan=None, kijun=None, senkou=None, offset=None, **kwargs):
+ def ichimoku(self, tenkan=None, kijun=None, senkou=None, include_chikou=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, 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, include_chikou=include_chikou, offset=offset, **kwargs)
self._add_prefix_suffix(result, **kwargs)
self._add_prefix_suffix(span, **kwargs)
self._append(result, **kwargs)
@@ -1416,11 +1424,11 @@ def chop(self, length=None, atr_length=None, scalar=None, drift=None, offset=Non
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):
+ def cksp(self, p=None, x=None, q=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 = 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, mamode=mamode, offset=offset, **kwargs)
return self._post_process(result, **kwargs)
def decay(self, length=None, mode=None, offset=None, **kwargs):
diff --git a/pandas_ta/custom.py b/pandas_ta/custom.py
new file mode 100644
index 00000000..4af5cc5f
--- /dev/null
+++ b/pandas_ta/custom.py
@@ -0,0 +1,226 @@
+# -*- coding: utf-8 -*-
+import importlib
+import os
+import sys
+import types
+
+from os.path import abspath, join, exists, basename, splitext
+from glob import glob
+
+import pandas_ta
+from pandas_ta import AnalysisIndicators
+
+
+def bind(function_name, function, method):
+ """
+ Helper function to bind the function and class method defined in a custom
+ indicator module to the active pandas_ta instance.
+
+ Args:
+ function_name (str): The name of the indicator within pandas_ta
+ function (fcn): The indicator function
+ method (fcn): The class method corresponding to the passed function
+ """
+ setattr(pandas_ta, function_name, function)
+ setattr(AnalysisIndicators, function_name, method)
+
+
+def create_dir(path, create_categories=True, verbose=True):
+ """
+ Helper function to setup a suitable folder structure for working with
+ custom indicators. You only need to call this once whenever you want to
+ setup a new custom indicators folder.
+
+ Args:
+ path (str): Full path to where you want your indicator tree
+ create_categories (bool): If True create category sub-folders
+ verbose (bool): If True print verbose output of results
+ """
+
+ # ensure that the passed directory exists / is readable
+ if not exists(path):
+ os.makedirs(path)
+ if verbose:
+ print(f"[i] Created main directory '{path}'.")
+
+ # list the contents of the directory
+ # dirs = glob(abspath(join(path, '*')))
+
+ # optionally add any missing category subdirectories
+ if create_categories:
+ for sd in [*pandas_ta.Category]:
+ d = abspath(join(path, sd))
+ if not exists(d):
+ os.makedirs(d)
+ if verbose:
+ dirname = basename(d)
+ print(f"[i] Created an empty sub-directory '{dirname}'.")
+
+
+def get_module_functions(module):
+ """
+ Helper function to get the functions of an imported module as a dictionary.
+
+ Args:
+ module: python module
+
+ Returns:
+ dict: module functions mapping
+ {
+ "func1_name": func1,
+ "func2_name": func2,...
+ }
+ """
+ module_functions = {}
+
+ for name, item in vars(module).items():
+ if isinstance(item, types.FunctionType):
+ module_functions[name] = item
+
+ return module_functions
+
+
+def import_dir(path, verbose=True):
+ # ensure that the passed directory exists / is readable
+ if not exists(path):
+ print(f"[X] Unable to read the directory '{path}'.")
+ return
+
+ # list the contents of the directory
+ dirs = glob(abspath(join(path, "*")))
+
+ # traverse full directory, importing all modules found there
+ for d in dirs:
+ dirname = basename(d)
+
+ # only look in directories which are valid pandas_ta categories
+ if dirname not in [*pandas_ta.Category]:
+ if verbose:
+ print(f"[i] Skipping the sub-directory '{dirname}' since it's not a valid pandas_ta category.")
+ continue
+
+ # for each module found in that category (directory)...
+ for module in glob(abspath(join(path, dirname, "*.py"))):
+ module_name = splitext(basename(module))[0]
+
+ # ensure that the supplied path is included in our python path
+ if d not in sys.path:
+ sys.path.append(d)
+
+ # (re)load the indicator module
+ module_functions = load_indicator_module(module_name)
+
+ # figure out which of the modules functions to bind to pandas_ta
+ fcn_callable = module_functions.get(module_name, None)
+ fcn_method_callable = module_functions.get(f"{module_name}_method", None)
+
+ if fcn_callable == None:
+ print(f"[X] Unable to find a function named '{module_name}' in the module '{module_name}.py'.")
+ continue
+ if fcn_method_callable == None:
+ missing_method = f"{module_name}_method"
+ print(f"[X] Unable to find a method function named '{missing_method}' in the module '{module_name}.py'.")
+ continue
+
+ # add it to the correct category if it's not there yet
+ if module_name not in pandas_ta.Category[dirname]:
+ pandas_ta.Category[dirname].append(module_name)
+
+ bind(module_name, fcn_callable, fcn_method_callable)
+ if verbose:
+ print(f"[i] Successfully imported the custom indicator '{module}' into category '{dirname}'.")
+
+
+import_dir.__doc__ = \
+"""
+Import a directory of custom indicators into pandas_ta
+
+Args:
+ path (str): Full path to your indicator tree
+ verbose (bool): If True verbose output of results
+
+This method allows you to experiment and develop your own technical analysis
+indicators in a separate local directory of your choice but use them seamlessly
+together with the existing pandas_ta functions just like if they were part of
+pandas_ta.
+
+If you at some late point would like to push them into the pandas_ta library
+you can do so very easily by following the step by step instruction here
+https://github.com/twopirllc/pandas-ta/issues/355.
+
+A brief example of usage:
+
+1. Loading the 'ta' module:
+>>> import pandas as pd
+>>> import pandas_ta as ta
+
+2. Create an empty directory on your machine where you want to work with your
+indicators. Invoke pandas_ta.custom.import_dir once to pre-populate it with
+sub-folders for all available indicator categories, e.g.:
+
+>>> import os
+>>> from os.path import abspath, join, expanduser
+>>> from pandas_ta.custom import create_dir, import_dir
+>>> ta_dir = abspath(join(expanduser("~"), "my_indicators"))
+>>> create_dir(ta_dir)
+
+3. You can now create your own custom indicator e.g. by copying existing
+ones from pandas_ta core module and modifying them.
+
+IMPORTANT: Each custom indicator should have a unique name and have both
+a) a function named exactly as the module, e.g. 'ni' if the module is ni.py
+b) a matching method used by AnalysisIndicators named as the module but
+ ending with '_method'. E.g. 'ni_method'
+
+In essence these modules should look exactly like the standard indicators
+available in categories under the pandas_ta-folder. The only difference will
+be an addition of a matching class method.
+
+For an example of the correct structure, look at the example ni.py in the
+examples folder.
+
+The ni.py indicator is a trend indicator so therefore we drop it into the
+sub-folder named trend. Thus we have a folder structure like this:
+
+~/my_indicators/
+│
+├── candles/
+.
+.
+└── trend/
+. └── ni.py
+.
+└── volume/
+
+4. We can now dynamically load all our custom indicators located in our
+designated indicators directory like this:
+
+>>> import_dir(ta_dir)
+
+If your custom indicator(s) loaded succesfully then it should behave exactly
+like all other native indicators in pandas_ta, including help functions.
+"""
+
+
+def load_indicator_module(name):
+ """
+ Helper function to (re)load an indicator module.
+
+ Returns:
+ dict: module functions mapping
+ {
+ "func1_name": func1,
+ "func2_name": func2,...
+ }
+
+ """
+ # load module
+ try:
+ module = importlib.import_module(name)
+ except Exception as ex:
+ print(f"[X] An error occurred when attempting to load module {name}: {ex}")
+ sys.exit(1)
+
+ # reload to refresh previously loaded module
+ module = importlib.reload(module)
+ return get_module_functions(module)
\ No newline at end of file
diff --git a/pandas_ta/momentum/apo.py b/pandas_ta/momentum/apo.py
index 60ceaf10..55c55e02 100644
--- a/pandas_ta/momentum/apo.py
+++ b/pandas_ta/momentum/apo.py
@@ -1,10 +1,10 @@
# -*- coding: utf-8 -*-
from pandas_ta import Imports
-from pandas_ta.overlap import sma
-from pandas_ta.utils import get_offset, verify_series
+from pandas_ta.overlap import ma
+from pandas_ta.utils import get_offset, tal_ma, verify_series
-def apo(close, fast=None, slow=None, offset=None, **kwargs):
+def apo(close, fast=None, slow=None, mamode=None, talib=None, offset=None, **kwargs):
"""Indicator: Absolute Price Oscillator (APO)"""
# Validate Arguments
fast = int(fast) if fast and fast > 0 else 12
@@ -12,17 +12,19 @@ def apo(close, fast=None, slow=None, offset=None, **kwargs):
if slow < fast:
fast, slow = slow, fast
close = verify_series(close, max(fast, slow))
+ mamode = mamode if isinstance(mamode, str) else "sma"
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import APO
- apo = APO(close, fast, slow)
+ apo = APO(close, fast, slow, tal_ma(mamode))
else:
- fastma = sma(close, length=fast)
- slowma = sma(close, length=slow)
+ fastma = ma(mamode, close, length=fast)
+ slowma = ma(mamode, close, length=slow)
apo = fastma - slowma
# Offset
@@ -62,6 +64,9 @@ def apo(close, fast=None, slow=None, offset=None, **kwargs):
close (pd.Series): Series of 'close's
fast (int): The short period. Default: 12
slow (int): The long period. Default: 26
+ mamode (str): See ```help(ta.ma)```. Default: 'sma'
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/momentum/bias.py b/pandas_ta/momentum/bias.py
index 093dbeac..3b300039 100644
--- a/pandas_ta/momentum/bias.py
+++ b/pandas_ta/momentum/bias.py
@@ -53,7 +53,7 @@ def bias(close, length=None, mamode=None, offset=None, **kwargs):
Args:
close (pd.Series): Series of 'close's
length (int): The period. Default: 26
- mamode (str): Options: 'ema', 'hma', 'rma', 'sma', 'wma'. Default: 'sma'
+ mamode (str): See ```help(ta.ma)```. Default: 'sma'
drift (int): The short period. Default: 1
offset (int): How many periods to offset the result. Default: 0
diff --git a/pandas_ta/momentum/bop.py b/pandas_ta/momentum/bop.py
index 5f901af1..8a8f3834 100644
--- a/pandas_ta/momentum/bop.py
+++ b/pandas_ta/momentum/bop.py
@@ -3,7 +3,7 @@
from pandas_ta.utils import get_offset, non_zero_range, verify_series
-def bop(open_, high, low, close, scalar=None, offset=None, **kwargs):
+def bop(open_, high, low, close, scalar=None, talib=None, offset=None, **kwargs):
"""Indicator: Balance of Power (BOP)"""
# Validate Arguments
open_ = verify_series(open_)
@@ -12,9 +12,10 @@ def bop(open_, high, low, close, scalar=None, offset=None, **kwargs):
close = verify_series(close)
scalar = float(scalar) if scalar else 1
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import BOP
bop = BOP(open_, high, low, close)
else:
@@ -56,6 +57,8 @@ def bop(open_, high, low, close, scalar=None, offset=None, **kwargs):
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
scalar (float): How much to magnify. Default: 1
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/momentum/cci.py b/pandas_ta/momentum/cci.py
index f8eec173..5b5370c3 100644
--- a/pandas_ta/momentum/cci.py
+++ b/pandas_ta/momentum/cci.py
@@ -5,7 +5,7 @@
from pandas_ta.utils import get_offset, verify_series
-def cci(high, low, close, length=None, c=None, offset=None, **kwargs):
+def cci(high, low, close, length=None, c=None, talib=None, offset=None, **kwargs):
"""Indicator: Commodity Channel Index (CCI)"""
# Validate Arguments
length = int(length) if length and length > 0 else 14
@@ -14,11 +14,12 @@ def cci(high, low, close, length=None, c=None, offset=None, **kwargs):
low = verify_series(low, length)
close = verify_series(close, length)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if high is None or low is None or close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import CCI
cci = CCI(high, low, close, length)
else:
@@ -71,6 +72,8 @@ def cci(high, low, close, length=None, c=None, offset=None, **kwargs):
close (pd.Series): Series of 'close's
length (int): It's period. Default: 14
c (float): Scaling Constant. Default: 0.015
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/momentum/cmo.py b/pandas_ta/momentum/cmo.py
index 6c02ced9..b14402fc 100644
--- a/pandas_ta/momentum/cmo.py
+++ b/pandas_ta/momentum/cmo.py
@@ -4,7 +4,7 @@
from pandas_ta.utils import get_drift, get_offset, verify_series
-def cmo(close, length=None, scalar=None, drift=None, offset=None, **kwargs):
+def cmo(close, length=None, scalar=None, talib=None, drift=None, offset=None, **kwargs):
"""Indicator: Chande Momentum Oscillator (CMO)"""
# Validate Arguments
length = int(length) if length and length > 0 else 14
@@ -12,11 +12,12 @@ def cmo(close, length=None, scalar=None, drift=None, offset=None, **kwargs):
close = verify_series(close, length)
drift = get_drift(drift)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import CMO
cmo = CMO(close, length)
else:
@@ -24,8 +25,7 @@ def cmo(close, length=None, scalar=None, drift=None, offset=None, **kwargs):
positive = mom.copy().clip(lower=0)
negative = mom.copy().clip(upper=0).abs()
- talib = kwargs.pop("talib", True)
- if talib:
+ if mode_tal:
pos_ = rma(positive, length)
neg_ = rma(negative, length)
else:
@@ -71,6 +71,9 @@ def cmo(close, length=None, scalar=None, drift=None, offset=None, **kwargs):
Args:
close (pd.Series): Series of 'close's
scalar (float): How much to magnify. Default: 100
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. If TA Lib is not installed but talib is True, it runs the Python
+ version TA Lib. Default: True
drift (int): The short period. Default: 1
offset (int): How many periods to offset the result. Default: 0
diff --git a/pandas_ta/momentum/dm.py b/pandas_ta/momentum/dm.py
index 0c234c70..3f442fa7 100644
--- a/pandas_ta/momentum/dm.py
+++ b/pandas_ta/momentum/dm.py
@@ -5,7 +5,7 @@
from pandas_ta.utils import get_offset, verify_series, get_drift, zero
-def dm(high, low, length=None, mamode=None, drift=None, offset=None, **kwargs):
+def dm(high, low, length=None, mamode=None, talib=None, drift=None, offset=None, **kwargs):
"""Indicator: DM"""
# Validate Arguments
length = int(length) if length and length > 0 else 14
@@ -14,13 +14,15 @@ def dm(high, low, length=None, mamode=None, drift=None, offset=None, **kwargs):
low = verify_series(low)
drift = get_drift(drift)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if high is None or low is None:
return
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import MINUS_DM, PLUS_DM
- pos, neg = PLUS_DM(high, low), MINUS_DM(high, low)
+ pos = PLUS_DM(high, low, length)
+ neg = MINUS_DM(high, low, length)
else:
up = high - high.shift(drift)
dn = low.shift(drift) - low
@@ -85,6 +87,9 @@ def dm(high, low, length=None, mamode=None, drift=None, offset=None, **kwargs):
Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
+ mamode (str): See ```help(ta.ma)```. Default: 'rma'
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
diff --git a/pandas_ta/momentum/fisher.py b/pandas_ta/momentum/fisher.py
index e15ac100..662bb37b 100644
--- a/pandas_ta/momentum/fisher.py
+++ b/pandas_ta/momentum/fisher.py
@@ -3,7 +3,7 @@
from numpy import nan as npNaN
from pandas import DataFrame, Series
from pandas_ta.overlap import hl2
-from pandas_ta.utils import get_offset, high_low_range, verify_series, zero
+from pandas_ta.utils import get_offset, high_low_range, verify_series
def fisher(high, low, length=None, signal=None, offset=None, **kwargs):
diff --git a/pandas_ta/momentum/inertia.py b/pandas_ta/momentum/inertia.py
index fd580e5a..a8cd7266 100644
--- a/pandas_ta/momentum/inertia.py
+++ b/pandas_ta/momentum/inertia.py
@@ -78,6 +78,9 @@ def inertia(close=None, high=None, low=None, length=None, rvi_length=None, scala
close (pd.Series): Series of 'close's
length (int): It's period. Default: 20
rvi_length (int): RVI period. Default: 14
+ refined (bool): Use 'refined' calculation. Default: False
+ thirds (bool): Use 'thirds' calculation. Default: False
+ mamode (str): See ```help(ta.ma)```. Default: 'ema'
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
diff --git a/pandas_ta/momentum/macd.py b/pandas_ta/momentum/macd.py
index 694bd453..8e6e2ced 100644
--- a/pandas_ta/momentum/macd.py
+++ b/pandas_ta/momentum/macd.py
@@ -5,7 +5,7 @@
from pandas_ta.utils import get_offset, verify_series, signals
-def macd(close, fast=None, slow=None, signal=None, offset=None, **kwargs):
+def macd(close, fast=None, slow=None, signal=None, talib=None, offset=None, **kwargs):
"""Indicator: Moving Average, Convergence/Divergence (MACD)"""
# Validate arguments
fast = int(fast) if fast and fast > 0 else 12
@@ -15,13 +15,16 @@ def macd(close, fast=None, slow=None, signal=None, offset=None, **kwargs):
fast, slow = slow, fast
close = verify_series(close, max(fast, slow, signal))
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if close is None: return
+ as_mode = kwargs.setdefault("asmode", False)
+
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import MACD
- macd, signalma, histogram = MACD(close, fast, slow)
+ macd, signalma, histogram = MACD(close, fast, slow, signal)
else:
fastma = ema(close, length=fast)
slowma = ema(close, length=slow)
@@ -30,6 +33,11 @@ def macd(close, fast=None, slow=None, signal=None, offset=None, **kwargs):
signalma = ema(close=macd.loc[macd.first_valid_index():,], length=signal)
histogram = macd - signalma
+ if as_mode:
+ macd = macd - signalma
+ signalma = ema(close=macd.loc[macd.first_valid_index():,], length=signal)
+ histogram = macd - signalma
+
# Offset
if offset != 0:
macd = macd.shift(offset)
@@ -47,16 +55,17 @@ def macd(close, fast=None, slow=None, signal=None, offset=None, **kwargs):
signalma.fillna(method=kwargs["fill_method"], inplace=True)
# Name and Categorize it
+ _asmode = "AS" if as_mode else ""
_props = f"_{fast}_{slow}_{signal}"
- macd.name = f"MACD{_props}"
- histogram.name = f"MACDh{_props}"
- signalma.name = f"MACDs{_props}"
+ macd.name = f"MACD{_asmode}{_props}"
+ histogram.name = f"MACD{_asmode}h{_props}"
+ signalma.name = f"MACD{_asmode}s{_props}"
macd.category = histogram.category = signalma.category = "momentum"
# Prepare DataFrame to return
data = {macd.name: macd, histogram.name: histogram, signalma.name: signalma}
df = DataFrame(data)
- df.name = f"MACD{_props}"
+ df.name = f"MACD{_asmode}{_props}"
df.category = macd.category
signal_indicators = kwargs.pop("signal_indicators", False)
@@ -105,6 +114,7 @@ def macd(close, fast=None, slow=None, signal=None, offset=None, **kwargs):
Sources:
https://www.tradingview.com/wiki/MACD_(Moving_Average_Convergence/Divergence)
+ AS Mode: https://tr.tradingview.com/script/YFlKXHnP/
Calculation:
Default Inputs:
@@ -114,14 +124,23 @@ def macd(close, fast=None, slow=None, signal=None, offset=None, **kwargs):
Signal = EMA(MACD, signal)
Histogram = MACD - Signal
+ if asmode:
+ MACD = MACD - Signal
+ Signal = EMA(MACD, signal)
+ Histogram = MACD - Signal
+
Args:
close (pd.Series): Series of 'close's
fast (int): The short period. Default: 12
slow (int): The long period. Default: 26
signal (int): The signal period. Default: 9
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
+ asmode (value, optional): When True, enables AS version of MACD.
+ Default: False
fillna (value, optional): pd.DataFrame.fillna(value)
fill_method (value, optional): Type of fill method
diff --git a/pandas_ta/momentum/mom.py b/pandas_ta/momentum/mom.py
index 3c1a8f52..e2f66382 100644
--- a/pandas_ta/momentum/mom.py
+++ b/pandas_ta/momentum/mom.py
@@ -3,17 +3,18 @@
from pandas_ta.utils import get_offset, verify_series
-def mom(close, length=None, offset=None, **kwargs):
+def mom(close, length=None, talib=None, offset=None, **kwargs):
"""Indicator: Momentum (MOM)"""
# Validate Arguments
length = int(length) if length and length > 0 else 10
close = verify_series(close, length)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import MOM
mom = MOM(close, length)
else:
@@ -53,6 +54,8 @@ def mom(close, length=None, offset=None, **kwargs):
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 1
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/momentum/ppo.py b/pandas_ta/momentum/ppo.py
index a144f585..a92f3ca1 100644
--- a/pandas_ta/momentum/ppo.py
+++ b/pandas_ta/momentum/ppo.py
@@ -2,10 +2,10 @@
from pandas import DataFrame
from pandas_ta import Imports
from pandas_ta.overlap import ma
-from pandas_ta.utils import get_offset, verify_series
+from pandas_ta.utils import get_offset, tal_ma, verify_series
-def ppo(close, fast=None, slow=None, signal=None, scalar=None, mamode=None, offset=None, **kwargs):
+def ppo(close, fast=None, slow=None, signal=None, scalar=None, mamode=None, talib=None, offset=None, **kwargs):
"""Indicator: Percentage Price Oscillator (PPO)"""
# Validate Arguments
fast = int(fast) if fast and fast > 0 else 12
@@ -17,13 +17,14 @@ def ppo(close, fast=None, slow=None, signal=None, scalar=None, mamode=None, offs
fast, slow = slow, fast
close = verify_series(close, max(fast, slow, signal))
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import PPO
- ppo = PPO(close, fast, slow)
+ ppo = PPO(close, fast, slow, tal_ma(mamode))
else:
fastma = ma(mamode, close, length=fast)
slowma = ma(mamode, close, length=slow)
@@ -90,7 +91,9 @@ def ppo(close, fast=None, slow=None, signal=None, scalar=None, mamode=None, offs
slow(int): The long period. Default: 26
signal(int): The signal period. Default: 9
scalar (float): How much to magnify. Default: 100
- mamode (str): Options: 'ema', 'hma', 'rma', 'sma', 'wma'. Default: 'sma'
+ mamode (str): See ```help(ta.ma)```. Default: 'sma'
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset(int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/momentum/qqe.py b/pandas_ta/momentum/qqe.py
index 1badab68..69be112f 100644
--- a/pandas_ta/momentum/qqe.py
+++ b/pandas_ta/momentum/qqe.py
@@ -143,8 +143,7 @@ def qqe(close, length=None, smooth=None, factor=None, mamode=None, drift=None, o
length (int): RSI period. Default: 14
smooth (int): RSI smoothing period. Default: 5
factor (float): QQE Factor. Default: 4.236
- mamode (str): Smoothing MA type: "ema", "hma", "rma", "sma" or "wma".
- Default: "ema"
+ mamode (str): See ```help(ta.ma)```. Default: 'sma'
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
diff --git a/pandas_ta/momentum/roc.py b/pandas_ta/momentum/roc.py
index 1fb62e7b..75f30d24 100644
--- a/pandas_ta/momentum/roc.py
+++ b/pandas_ta/momentum/roc.py
@@ -4,18 +4,19 @@
from pandas_ta.utils import get_offset, verify_series
-def roc(close, length=None, scalar=None, offset=None, **kwargs):
+def roc(close, length=None, scalar=None, talib=None, offset=None, **kwargs):
"""Indicator: Rate of Change (ROC)"""
# Validate Arguments
length = int(length) if length and length > 0 else 10
scalar = float(scalar) if scalar and scalar > 0 else 100
close = verify_series(close, length)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import ROC
roc = ROC(close, length)
else:
@@ -57,6 +58,9 @@ def roc(close, length=None, scalar=None, offset=None, **kwargs):
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 1
+ scalar (float): How much to magnify. Default: 100
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/momentum/rsi.py b/pandas_ta/momentum/rsi.py
index c2b747a8..a8978efb 100644
--- a/pandas_ta/momentum/rsi.py
+++ b/pandas_ta/momentum/rsi.py
@@ -5,7 +5,7 @@
from pandas_ta.utils import get_drift, get_offset, verify_series, signals
-def rsi(close, length=None, scalar=None, drift=None, offset=None, **kwargs):
+def rsi(close, length=None, scalar=None, talib=None, drift=None, offset=None, **kwargs):
"""Indicator: Relative Strength Index (RSI)"""
# Validate arguments
length = int(length) if length and length > 0 else 14
@@ -13,11 +13,12 @@ def rsi(close, length=None, scalar=None, drift=None, offset=None, **kwargs):
close = verify_series(close, length)
drift = get_drift(drift)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import RSI
rsi = RSI(close, length)
else:
@@ -99,6 +100,8 @@ def rsi(close, length=None, scalar=None, drift=None, offset=None, **kwargs):
close (pd.Series): Series of 'close's
length (int): It's period. Default: 14
scalar (float): How much to magnify. Default: 100
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
diff --git a/pandas_ta/momentum/smi.py b/pandas_ta/momentum/smi.py
index a652ccad..ba8c5257 100644
--- a/pandas_ta/momentum/smi.py
+++ b/pandas_ta/momentum/smi.py
@@ -20,8 +20,9 @@ def smi(close, fast=None, slow=None, signal=None, scalar=None, offset=None, **kw
if close is None: return
# Calculate Result
- smi = tsi(close, fast=fast, slow=slow, scalar=scalar)
- signalma = ema(smi, signal)
+ tsi_df = tsi(close, fast=fast, slow=slow, signal=signal, scalar=scalar)
+ smi = tsi_df.iloc[:, 0]
+ signalma = tsi_df.iloc[:, 1]
osc = smi - signalma
# Offset
diff --git a/pandas_ta/momentum/squeeze.py b/pandas_ta/momentum/squeeze.py
index 514d149a..2fc3ace3 100644
--- a/pandas_ta/momentum/squeeze.py
+++ b/pandas_ta/momentum/squeeze.py
@@ -9,7 +9,7 @@
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, mamode=None, offset=None, **kwargs):
"""Indicator: Squeeze Momentum (SQZ)"""
# Validate arguments
bb_length = int(bb_length) if bb_length and bb_length > 0 else 20
@@ -30,7 +30,7 @@ def squeeze(high, low, close, bb_length=None, bb_std=None, kc_length=None, kc_sc
asint = kwargs.pop("asint", True)
detailed = kwargs.pop("detailed", False)
lazybear = kwargs.pop("lazybear", False)
- mamode = kwargs.pop("mamode", "sma").lower()
+ mamode = mamode if isinstance(mamode, str) else "sma"
def simplify_columns(df, n=3):
df.columns = df.columns.str.lower()
diff --git a/pandas_ta/momentum/squeeze_pro.py b/pandas_ta/momentum/squeeze_pro.py
index 61cefc68..d2d591f5 100644
--- a/pandas_ta/momentum/squeeze_pro.py
+++ b/pandas_ta/momentum/squeeze_pro.py
@@ -9,7 +9,7 @@
from pandas_ta.utils import unsigned_differences, verify_series
-def squeeze_pro(high, low, close, bb_length=None, bb_std=None, kc_length=None, kc_scalar_wide=None, kc_scalar_normal=None, kc_scalar_narrow=None, mom_length=None, mom_smooth=None, use_tr=None, offset=None, **kwargs):
+def squeeze_pro(high, low, close, bb_length=None, bb_std=None, kc_length=None, kc_scalar_wide=None, kc_scalar_normal=None, kc_scalar_narrow=None, mom_length=None, mom_smooth=None, use_tr=None, mamode=None, offset=None, **kwargs):
"""Indicator: Squeeze Momentum (SQZ) PRO"""
# Validate arguments
bb_length = int(bb_length) if bb_length and bb_length > 0 else 20
@@ -35,7 +35,7 @@ def squeeze_pro(high, low, close, bb_length=None, bb_std=None, kc_length=None, k
use_tr = kwargs.setdefault("tr", True)
asint = kwargs.pop("asint", True)
detailed = kwargs.pop("detailed", False)
- mamode = kwargs.pop("mamode", "sma").lower()
+ mamode = mamode if isinstance(mamode, str) else "sma"
def simplify_columns(df, n=3):
df.columns = df.columns.str.lower()
diff --git a/pandas_ta/momentum/stoch.py b/pandas_ta/momentum/stoch.py
index 2b55b55f..823c3329 100644
--- a/pandas_ta/momentum/stoch.py
+++ b/pandas_ta/momentum/stoch.py
@@ -1,10 +1,10 @@
# -*- coding: utf-8 -*-
from pandas import DataFrame
-from pandas_ta.overlap import sma
+from pandas_ta.overlap import ma
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, mamode=None, offset=None, **kwargs):
"""Indicator: Stochastic Oscillator (STOCH)"""
# Validate arguments
k = k if k and k > 0 else 14
@@ -15,6 +15,7 @@ def stoch(high, low, close, k=None, d=None, smooth_k=None, offset=None, **kwargs
low = verify_series(low, _length)
close = verify_series(close, _length)
offset = get_offset(offset)
+ mamode = mamode if isinstance(mamode, str) else "sma"
if high is None or low is None or close is None: return
@@ -25,8 +26,8 @@ def stoch(high, low, close, k=None, d=None, smooth_k=None, offset=None, **kwargs
stoch = 100 * (close - lowest_low)
stoch /= non_zero_range(highest_high, lowest_low)
- stoch_k = sma(stoch, length=smooth_k)
- stoch_d = sma(stoch_k, length=d)
+ stoch_k = ma(mamode, stoch.loc[stoch.first_valid_index():,], length=smooth_k)
+ stoch_d = ma(mamode, stoch_k.loc[stoch_k.first_valid_index():,], length=d)
# Offset
if offset != 0:
@@ -53,7 +54,6 @@ def stoch(high, low, close, k=None, d=None, smooth_k=None, offset=None, **kwargs
df = DataFrame(data)
df.name = f"{_name}{_props}"
df.category = stoch_k.category
-
return df
@@ -91,6 +91,7 @@ def stoch(high, low, close, k=None, d=None, smooth_k=None, offset=None, **kwargs
k (int): The Fast %K period. Default: 14
d (int): The Slow %K period. Default: 3
smooth_k (int): The Slow %D period. Default: 3
+ mamode (str): See ```help(ta.ma)```. Default: 'sma'
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/momentum/stochrsi.py b/pandas_ta/momentum/stochrsi.py
index cdd32b0f..08414848 100644
--- a/pandas_ta/momentum/stochrsi.py
+++ b/pandas_ta/momentum/stochrsi.py
@@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
from pandas import DataFrame
from .rsi import rsi
-from pandas_ta.overlap import sma
+from pandas_ta.overlap import ma
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, mamode=None, offset=None, **kwargs):
"""Indicator: Stochastic RSI Oscillator (STOCHRSI)"""
# Validate arguments
length = length if length and length > 0 else 14
@@ -14,6 +14,7 @@ def stochrsi(close, length=None, rsi_length=None, k=None, d=None, offset=None, *
d = d if d and d > 0 else 3
close = verify_series(close, max(length, rsi_length, k, d))
offset = get_offset(offset)
+ mamode = mamode if isinstance(mamode, str) else "sma"
if close is None: return
@@ -25,8 +26,8 @@ def stochrsi(close, length=None, rsi_length=None, k=None, d=None, offset=None, *
stoch = 100 * (rsi_ - lowest_rsi)
stoch /= non_zero_range(highest_rsi, lowest_rsi)
- stochrsi_k = sma(stoch, length=k)
- stochrsi_d = sma(stochrsi_k, length=d)
+ stochrsi_k = ma(mamode, stoch, length=k)
+ stochrsi_d = ma(mamode, stochrsi_k, length=d)
# Offset
if offset != 0:
@@ -92,6 +93,7 @@ def stochrsi(close, length=None, rsi_length=None, k=None, d=None, offset=None, *
rsi_length (int): RSI period. Default: 14
k (int): The Fast %K period. Default: 3
d (int): The Slow %K period. Default: 3
+ mamode (str): See ```help(ta.ma)```. Default: 'sma'
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/momentum/tsi.py b/pandas_ta/momentum/tsi.py
index 587e3ebd..6747c7d1 100644
--- a/pandas_ta/momentum/tsi.py
+++ b/pandas_ta/momentum/tsi.py
@@ -1,19 +1,22 @@
# -*- coding: utf-8 -*-
-from pandas_ta.overlap import ema
+from pandas import DataFrame
+from pandas_ta.overlap import ema, ma
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, signal=None, scalar=None, mamode=None, drift=None, offset=None, **kwargs):
"""Indicator: True Strength Index (TSI)"""
# Validate Arguments
fast = int(fast) if fast and fast > 0 else 13
slow = int(slow) if slow and slow > 0 else 25
+ signal = int(signal) if signal and signal > 0 else 13
# if slow < fast:
# fast, slow = slow, fast
scalar = float(scalar) if scalar else 100
close = verify_series(close, max(fast, slow))
drift = get_drift(drift)
offset = get_offset(offset)
+ mamode = mamode if isinstance(mamode, str) else "ema"
if "length" in kwargs: kwargs.pop("length")
if close is None: return
@@ -28,22 +31,32 @@ def tsi(close, fast=None, slow=None, scalar=None, drift=None, offset=None, **kwa
abs_fast_slow_ema = ema(close=abs_slow_ema, length=fast, **kwargs)
tsi = scalar * fast_slow_ema / abs_fast_slow_ema
+ tsi_signal = ma(mamode, tsi, length=signal)
# Offset
if offset != 0:
tsi = tsi.shift(offset)
+ tsi_signal = tsi_signal.shift(offset)
# Handle fills
if "fillna" in kwargs:
tsi.fillna(kwargs["fillna"], inplace=True)
+ tsi_signal.fillna(kwargs["fillna"], inplace=True)
if "fill_method" in kwargs:
tsi.fillna(method=kwargs["fill_method"], inplace=True)
+ tsi_signal.fillna(method=kwargs["fill_method"], inplace=True)
# Name and Categorize it
- tsi.name = f"TSI_{fast}_{slow}"
- tsi.category = "momentum"
+ tsi.name = f"TSI_{fast}_{slow}_{signal}"
+ tsi_signal.name = f"TSIs_{fast}_{slow}_{signal}"
+ tsi.category = tsi_signal.category = "momentum"
- return tsi
+ # Prepare DataFrame to return
+ df = DataFrame({tsi.name: tsi, tsi_signal.name: tsi_signal})
+ df.name = f"TSI_{fast}_{slow}_{signal}"
+ df.category = "momentum"
+
+ return df
tsi.__doc__ = \
@@ -58,7 +71,7 @@ def tsi(close, fast=None, slow=None, scalar=None, drift=None, offset=None, **kwa
Calculation:
Default Inputs:
- fast=13, slow=25, scalar=100, drift=1
+ fast=13, slow=25, signal=13, scalar=100, drift=1
EMA = Exponential Moving Average
diff = close.diff(drift)
@@ -69,12 +82,16 @@ def tsi(close, fast=None, slow=None, scalar=None, drift=None, offset=None, **kwa
abema = abs_diff_fast_slow_ema = EMA(abs_diff_slow_ema, fast)
TSI = scalar * fast_slow_ema / abema
+ Signal = EMA(TSI, signal)
Args:
close (pd.Series): Series of 'close's
fast (int): The short period. Default: 13
slow (int): The long period. Default: 25
+ signal (int): The signal period. Default: 13
scalar (float): How much to magnify. Default: 100
+ mamode (str): Moving Average of TSI Signal Line.
+ See ```help(ta.ma)```. Default: 'ema'
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
@@ -83,5 +100,5 @@ def tsi(close, fast=None, slow=None, scalar=None, drift=None, offset=None, **kwa
fill_method (value, optional): Type of fill method
Returns:
- pd.Series: New feature generated.
+ pd.DataFrame: tsi, signal.
"""
diff --git a/pandas_ta/momentum/uo.py b/pandas_ta/momentum/uo.py
index 3da23d7b..f58691a7 100644
--- a/pandas_ta/momentum/uo.py
+++ b/pandas_ta/momentum/uo.py
@@ -4,7 +4,7 @@
from pandas_ta.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, talib=None, drift=None, offset=None, **kwargs):
"""Indicator: Ultimate Oscillator (UO)"""
# Validate arguments
fast = int(fast) if fast and fast > 0 else 7
@@ -19,13 +19,14 @@ def uo(high, low, close, fast=None, medium=None, slow=None, fast_w=None, medium_
close = verify_series(close, _length)
drift = get_drift(drift)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if high is None or low is None or close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import ULTOSC
- uo = ULTOSC(high, low, close)
+ uo = ULTOSC(high, low, close, fast, medium, slow)
else:
tdf = DataFrame({
"high": high,
@@ -101,6 +102,8 @@ def uo(high, low, close, fast=None, medium=None, slow=None, fast_w=None, medium_
fast_w (float): The Fast %K period. Default: 4.0
medium_w (float): The Slow %K period. Default: 2.0
slow_w (float): The Slow %D period. Default: 1.0
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
diff --git a/pandas_ta/momentum/willr.py b/pandas_ta/momentum/willr.py
index fe69cb77..d3e87f77 100644
--- a/pandas_ta/momentum/willr.py
+++ b/pandas_ta/momentum/willr.py
@@ -3,7 +3,7 @@
from pandas_ta.utils import get_offset, verify_series
-def willr(high, low, close, length=None, offset=None, **kwargs):
+def willr(high, low, close, length=None, talib=None, offset=None, **kwargs):
"""Indicator: William's Percent R (WILLR)"""
# Validate arguments
length = int(length) if length and length > 0 else 14
@@ -13,11 +13,12 @@ def willr(high, low, close, length=None, offset=None, **kwargs):
low = verify_series(low, _length)
close = verify_series(close, _length)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if high is None or low is None or close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import WILLR
willr = WILLR(high, low, close, length)
else:
@@ -65,6 +66,8 @@ def willr(high, low, close, length=None, offset=None, **kwargs):
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
length (int): It's period. Default: 14
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/overlap/__init__.py b/pandas_ta/overlap/__init__.py
index 4c098ff7..7a0f5ec2 100644
--- a/pandas_ta/overlap/__init__.py
+++ b/pandas_ta/overlap/__init__.py
@@ -9,6 +9,7 @@
from .hma import hma
from .hwma import hwma
from .ichimoku import ichimoku
+from .jma import jma
from .kama import kama
from .linreg import linreg
from .ma import ma
diff --git a/pandas_ta/overlap/dema.py b/pandas_ta/overlap/dema.py
index 29deb5e4..5ce8e038 100644
--- a/pandas_ta/overlap/dema.py
+++ b/pandas_ta/overlap/dema.py
@@ -4,17 +4,18 @@
from pandas_ta.utils import get_offset, verify_series
-def dema(close, length=None, offset=None, **kwargs):
+def dema(close, length=None, talib=None, offset=None, **kwargs):
"""Indicator: Double Exponential Moving Average (DEMA)"""
# Validate Arguments
length = int(length) if length and length > 0 else 10
close = verify_series(close, length)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import DEMA
dema = DEMA(close, length)
else:
@@ -60,6 +61,8 @@ def dema(close, length=None, offset=None, **kwargs):
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/overlap/ema.py b/pandas_ta/overlap/ema.py
index 105f856f..507aa9f2 100644
--- a/pandas_ta/overlap/ema.py
+++ b/pandas_ta/overlap/ema.py
@@ -4,7 +4,7 @@
from pandas_ta.utils import get_offset, verify_series
-def ema(close, length=None, offset=None, **kwargs):
+def ema(close, length=None, talib=None, offset=None, **kwargs):
"""Indicator: Exponential Moving Average (EMA)"""
# Validate Arguments
length = int(length) if length and length > 0 else 10
@@ -12,11 +12,12 @@ def ema(close, length=None, offset=None, **kwargs):
sma = kwargs.pop("sma", True)
close = verify_series(close, length)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import EMA
ema = EMA(close, length)
else:
@@ -69,6 +70,8 @@ def ema(close, length=None, offset=None, **kwargs):
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/overlap/hilo.py b/pandas_ta/overlap/hilo.py
index 5c7250ae..128c9ef1 100644
--- a/pandas_ta/overlap/hilo.py
+++ b/pandas_ta/overlap/hilo.py
@@ -115,7 +115,7 @@ def hilo(high, low, close, high_length=None, low_length=None, mamode=None, offse
close (pd.Series): Series of 'close's
high_length (int): It's period. Default: 13
low_length (int): It's period. Default: 21
- mamode (str): Options: 'sma' or 'ema'. Default: 'sma'
+ mamode (str): See ```help(ta.ma)```. Default: 'sma'
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/overlap/hlc3.py b/pandas_ta/overlap/hlc3.py
index e22046bb..087ed1dc 100644
--- a/pandas_ta/overlap/hlc3.py
+++ b/pandas_ta/overlap/hlc3.py
@@ -3,16 +3,17 @@
from pandas_ta.utils import get_offset, verify_series
-def hlc3(high, low, close, offset=None, **kwargs):
+def hlc3(high, low, close, talib=None, offset=None, **kwargs):
"""Indicator: HLC3"""
# Validate Arguments
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import TYPPRICE
hlc3 = TYPPRICE(high, low, close)
else:
diff --git a/pandas_ta/overlap/ichimoku.py b/pandas_ta/overlap/ichimoku.py
index 24547419..7f2e9257 100644
--- a/pandas_ta/overlap/ichimoku.py
+++ b/pandas_ta/overlap/ichimoku.py
@@ -4,7 +4,7 @@
from pandas_ta.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, include_chikou=True, offset=None, **kwargs):
"""Indicator: Ichimoku Kinkō Hyō (Ichimoku)"""
tenkan = int(tenkan) if tenkan and tenkan > 0 else 9
kijun = int(kijun) if kijun and kijun > 0 else 26
@@ -14,6 +14,8 @@ def ichimoku(high, low, close, tenkan=None, kijun=None, senkou=None, offset=None
low = verify_series(low, _length)
close = verify_series(close, _length)
offset = get_offset(offset)
+ if not kwargs.get("lookahead", True):
+ include_chikou = False
if high is None or low is None or close is None: return None, None
@@ -65,8 +67,10 @@ def ichimoku(high, low, close, tenkan=None, kijun=None, senkou=None, offset=None
span_b.name: span_b,
tenkan_sen.name: tenkan_sen,
kijun_sen.name: kijun_sen,
- chikou_span.name: chikou_span,
}
+ if include_chikou:
+ data[chikou_span.name] = chikou_span
+
ichimokudf = DataFrame(data)
ichimokudf.name = f"ICHIMOKU_{tenkan}_{kijun}_{senkou}"
ichimokudf.category = "overlap"
@@ -121,6 +125,7 @@ def ichimoku(high, low, close, tenkan=None, kijun=None, senkou=None, offset=None
tenkan (int): Tenkan period. Default: 9
kijun (int): Kijun period. Default: 26
senkou (int): Senkou period. Default: 52
+ include_chikou (bool): Whether to include chikou component. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/overlap/jma.py b/pandas_ta/overlap/jma.py
new file mode 100644
index 00000000..28afbab2
--- /dev/null
+++ b/pandas_ta/overlap/jma.py
@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+from numpy import average as npAverage
+from numpy import nan as npNaN
+from numpy import log as npLog
+from numpy import power as npPower
+from numpy import sqrt as npSqrt
+from numpy import zeros_like as npZeroslike
+from pandas import Series
+from pandas_ta.utils import get_offset, verify_series
+
+
+def jma(close, length=None, phase=None, offset=None, **kwargs):
+ """Indicator: Jurik Moving Average (JMA)"""
+ # Validate Arguments
+ _length = int(length) if length and length > 0 else 7
+ phase = float(phase) if phase and phase != 0 else 0
+ close = verify_series(close, _length)
+ offset = get_offset(offset)
+ if close is None: return
+
+ # Define base variables
+ jma = npZeroslike(close)
+ volty = npZeroslike(close)
+ v_sum = npZeroslike(close)
+
+ kv = det0 = det1 = ma2 = 0.0
+ jma[0] = ma1 = uBand = lBand = close[0]
+
+ # Static variables
+ sum_length = 10
+ length = 0.5 * (_length - 1)
+ pr = 0.5 if phase < -100 else 2.5 if phase > 100 else 1.5 + phase * 0.01
+ length1 = max((npLog(npSqrt(length)) / npLog(2.0)) + 2.0, 0)
+ pow1 = max(length1 - 2.0, 0.5)
+ length2 = length1 * npSqrt(length)
+ bet = length2 / (length2 + 1)
+ beta = 0.45 * (_length - 1) / (0.45 * (_length - 1) + 2.0)
+
+ m = close.shape[0]
+ for i in range(1, m):
+ price = close[i]
+
+ # Price volatility
+ del1 = price - uBand
+ del2 = price - lBand
+ volty[i] = max(abs(del1),abs(del2)) if abs(del1)!=abs(del2) else 0
+
+ # Relative price volatility factor
+ v_sum[i] = v_sum[i - 1] + (volty[i] - volty[max(i - sum_length, 0)]) / sum_length
+ avg_volty = npAverage(v_sum[max(i - 65, 0):i + 1])
+ d_volty = 0 if avg_volty ==0 else volty[i] / avg_volty
+ r_volty = max(1.0, min(npPower(length1, 1 / pow1), d_volty))
+
+ # Jurik volatility bands
+ pow2 = npPower(r_volty, pow1)
+ kv = npPower(bet, npSqrt(pow2))
+ uBand = price if (del1 > 0) else price - (kv * del1)
+ lBand = price if (del2 < 0) else price - (kv * del2)
+
+ # Jurik Dynamic Factor
+ power = npPower(r_volty, pow1)
+ alpha = npPower(beta, power)
+
+ # 1st stage - prelimimary smoothing by adaptive EMA
+ ma1 = ((1 - alpha) * price) + (alpha * ma1)
+
+ # 2nd stage - one more prelimimary smoothing by Kalman filter
+ det0 = ((price - ma1) * (1 - beta)) + (beta * det0)
+ ma2 = ma1 + pr * det0
+
+ # 3rd stage - final smoothing by unique Jurik adaptive filter
+ det1 = ((ma2 - jma[i - 1]) * (1 - alpha) * (1 - alpha)) + (alpha * alpha * det1)
+ jma[i] = jma[i-1] + det1
+
+ # Remove initial lookback data and convert to pandas frame
+ jma[0:_length - 1] = npNaN
+ jma = Series(jma, index=close.index)
+
+ # Offset
+ if offset != 0:
+ jma = jma.shift(offset)
+
+ # Handle fills
+ if "fillna" in kwargs:
+ jma.fillna(kwargs["fillna"], inplace=True)
+ if "fill_method" in kwargs:
+ jma.fillna(method=kwargs["fill_method"], inplace=True)
+
+ # Name & Category
+ jma.name = f"JMA_{_length}_{phase}"
+ jma.category = "overlap"
+
+ return jma
+
+
+jma.__doc__ = \
+"""Jurik Moving Average Average (JMA)
+
+Mark Jurik's Moving Average (JMA) attempts to eliminate noise to see the "true"
+underlying activity. It has extremely low lag, is very smooth and is responsive
+to market gaps.
+
+Sources:
+ https://c.mql5.com/forextsd/forum/164/jurik_1.pdf
+ https://www.prorealcode.com/prorealtime-indicators/jurik-volatility-bands/
+
+Calculation:
+ Default Inputs:
+ length=7, phase=0
+
+Args:
+ close (pd.Series): Series of 'close's
+ length (int): Period of calculation. Default: 7
+ phase (float): How heavy/light the average is [-100, 100]. Default: 0
+ offset (int): How many lengths to offset the result. Default: 0
+
+Kwargs:
+ fillna (value, optional): pd.DataFrame.fillna(value)
+ fill_method (value, optional): Type of fill method
+
+Returns:
+ pd.Series: New feature generated.
+"""
diff --git a/pandas_ta/overlap/linreg.py b/pandas_ta/overlap/linreg.py
index 00f943b5..c6f00876 100644
--- a/pandas_ta/overlap/linreg.py
+++ b/pandas_ta/overlap/linreg.py
@@ -3,7 +3,7 @@
from numpy import arctan as npAtan
from numpy import nan as npNaN
from numpy import pi as npPi
-from numpy.lib.stride_tricks import sliding_window_view
+from numpy.version import version as npVersion
from pandas import Series
from pandas_ta.utils import get_offset, verify_series
@@ -54,7 +54,19 @@ def linear_regression(series):
return m * length + b if tsf else m * (length - 1) + b
- linreg_ = [linear_regression(_) for _ in sliding_window_view(npArray(close), length)]
+ def rolling_window(array, length):
+ """https://github.com/twopirllc/pandas-ta/issues/285"""
+ strides = array.strides + (array.strides[-1],)
+ shape = array.shape[:-1] + (array.shape[-1] - length + 1, length)
+ return as_strided(array, shape=shape, strides=strides)
+
+ if npVersion >= "1.20.0":
+ from numpy.lib.stride_tricks import sliding_window_view
+ linreg_ = [linear_regression(_) for _ in sliding_window_view(npArray(close), length)]
+ else:
+ from numpy.lib.stride_tricks import as_strided
+ linreg_ = [linear_regression(_) for _ in rolling_window(npArray(close), length)]
+
linreg = Series([npNaN] * (length - 1) + linreg_, index=close.index)
# Offset
diff --git a/pandas_ta/overlap/midpoint.py b/pandas_ta/overlap/midpoint.py
index 26dad4ae..efd9cc11 100644
--- a/pandas_ta/overlap/midpoint.py
+++ b/pandas_ta/overlap/midpoint.py
@@ -3,18 +3,19 @@
from pandas_ta.utils import get_offset, verify_series
-def midpoint(close, length=None, offset=None, **kwargs):
+def midpoint(close, length=None, talib=None, offset=None, **kwargs):
"""Indicator: Midpoint"""
# Validate arguments
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
close = verify_series(close, max(length, min_periods))
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import MIDPOINT
midpoint = MIDPOINT(close, length)
else:
diff --git a/pandas_ta/overlap/midprice.py b/pandas_ta/overlap/midprice.py
index 633f1338..39b775e6 100644
--- a/pandas_ta/overlap/midprice.py
+++ b/pandas_ta/overlap/midprice.py
@@ -3,7 +3,7 @@
from pandas_ta.utils import get_offset, verify_series
-def midprice(high, low, length=None, offset=None, **kwargs):
+def midprice(high, low, length=None, talib=None, offset=None, **kwargs):
"""Indicator: Midprice"""
# Validate arguments
length = int(length) if length and length > 0 else 2
@@ -12,11 +12,12 @@ def midprice(high, low, length=None, offset=None, **kwargs):
high = verify_series(high, _length)
low = verify_series(low, _length)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if high is None or low is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import MIDPRICE
midprice = MIDPRICE(high, low, length)
else:
diff --git a/pandas_ta/overlap/sma.py b/pandas_ta/overlap/sma.py
index 72760de2..dbcf8cbe 100644
--- a/pandas_ta/overlap/sma.py
+++ b/pandas_ta/overlap/sma.py
@@ -3,18 +3,19 @@
from pandas_ta.utils import get_offset, verify_series
-def sma(close, length=None, offset=None, **kwargs):
+def sma(close, length=None, talib=None, offset=None, **kwargs):
"""Indicator: Simple Moving Average (SMA)"""
# Validate Arguments
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
close = verify_series(close, max(length, min_periods))
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import SMA
sma = SMA(close, length)
else:
@@ -54,6 +55,8 @@ def sma(close, length=None, offset=None, **kwargs):
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/overlap/t3.py b/pandas_ta/overlap/t3.py
index eabec716..0ceae2d0 100644
--- a/pandas_ta/overlap/t3.py
+++ b/pandas_ta/overlap/t3.py
@@ -4,20 +4,21 @@
from pandas_ta.utils import get_offset, verify_series
-def t3(close, length=None, a=None, offset=None, **kwargs):
+def t3(close, length=None, a=None, talib=None, offset=None, **kwargs):
"""Indicator: T3"""
# Validate Arguments
length = int(length) if length and length > 0 else 10
a = float(a) if a and a > 0 and a < 1 else 0.7
close = verify_series(close, length)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import T3
- t3 = T3(close, length)
+ t3 = T3(close, length, a)
else:
c1 = -a * a**2
c2 = 3 * a**2 + 3 * a**3
@@ -77,6 +78,8 @@ def t3(close, length=None, a=None, offset=None, **kwargs):
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
a (float): 0 < a < 1. Default: 0.7
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/overlap/tema.py b/pandas_ta/overlap/tema.py
index 833cae5e..dfd043ac 100644
--- a/pandas_ta/overlap/tema.py
+++ b/pandas_ta/overlap/tema.py
@@ -4,17 +4,18 @@
from pandas_ta.utils import get_offset, verify_series
-def tema(close, length=None, offset=None, **kwargs):
+def tema(close, length=None, talib=None, offset=None, **kwargs):
"""Indicator: Triple Exponential Moving Average (TEMA)"""
# Validate Arguments
length = int(length) if length and length > 0 else 10
close = verify_series(close, length)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import TEMA
tema = TEMA(close, length)
else:
@@ -60,6 +61,8 @@ def tema(close, length=None, offset=None, **kwargs):
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/overlap/trima.py b/pandas_ta/overlap/trima.py
index e424e591..f7a36725 100644
--- a/pandas_ta/overlap/trima.py
+++ b/pandas_ta/overlap/trima.py
@@ -4,17 +4,18 @@
from pandas_ta.utils import get_offset, verify_series
-def trima(close, length=None, offset=None, **kwargs):
+def trima(close, length=None, talib=None, offset=None, **kwargs):
"""Indicator: Triangular Moving Average (TRIMA)"""
# Validate Arguments
length = int(length) if length and length > 0 else 10
close = verify_series(close, length)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import TRIMA
trima = TRIMA(close, length)
else:
@@ -61,6 +62,8 @@ def trima(close, length=None, offset=None, **kwargs):
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/overlap/wcp.py b/pandas_ta/overlap/wcp.py
index 5d92ce84..fa781707 100644
--- a/pandas_ta/overlap/wcp.py
+++ b/pandas_ta/overlap/wcp.py
@@ -3,16 +3,17 @@
from pandas_ta.utils import get_offset, verify_series
-def wcp(high, low, close, offset=None, **kwargs):
+def wcp(high, low, close, talib=None, offset=None, **kwargs):
"""Indicator: Weighted Closing Price (WCP)"""
# Validate Arguments
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import WCLPRICE
wcp = WCLPRICE(high, low, close)
else:
@@ -51,6 +52,8 @@ def wcp(high, low, close, offset=None, **kwargs):
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/overlap/wma.py b/pandas_ta/overlap/wma.py
index a5cfe601..6f8dcb68 100644
--- a/pandas_ta/overlap/wma.py
+++ b/pandas_ta/overlap/wma.py
@@ -4,18 +4,19 @@
from pandas_ta.utils import get_offset, verify_series
-def wma(close, length=None, asc=None, offset=None, **kwargs):
+def wma(close, length=None, asc=None, talib=None, offset=None, **kwargs):
"""Indicator: Weighted Moving Average (WMA)"""
# Validate Arguments
length = int(length) if length and length > 0 else 10
asc = asc if asc else True
close = verify_series(close, length)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import WMA
wma = WMA(close, length)
else:
@@ -78,6 +79,8 @@ def _compute(x):
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
asc (bool): Recent values weigh more. Default: True
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/statistics/stdev.py b/pandas_ta/statistics/stdev.py
index 9fff9288..d5c2ddfa 100644
--- a/pandas_ta/statistics/stdev.py
+++ b/pandas_ta/statistics/stdev.py
@@ -5,18 +5,19 @@
from pandas_ta.utils import get_offset, verify_series
-def stdev(close, length=None, ddof=None, offset=None, **kwargs):
+def stdev(close, length=None, ddof=None, talib=None, offset=None, **kwargs):
"""Indicator: Standard Deviation"""
# Validate Arguments
length = int(length) if length and length > 0 else 30
- ddof = int(ddof) if ddof and ddof >= 0 and ddof < length else 1
+ ddof = int(ddof) if isinstance(ddof, int) and ddof >= 0 and ddof < length else 1
close = verify_series(close, length)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import STDDEV
stdev = STDDEV(close, length)
else:
@@ -56,6 +57,8 @@ def stdev(close, length=None, ddof=None, offset=None, **kwargs):
ddof (int): Delta Degrees of Freedom.
The divisor used in calculations is N - ddof,
where N represents the number of elements. Default: 1
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
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 ffa6c99c..520f7da0 100644
--- a/pandas_ta/statistics/variance.py
+++ b/pandas_ta/statistics/variance.py
@@ -3,19 +3,20 @@
from pandas_ta.utils import get_offset, verify_series
-def variance(close, length=None, ddof=None, offset=None, **kwargs):
+def variance(close, length=None, ddof=None, talib=None, offset=None, **kwargs):
"""Indicator: Variance"""
# Validate Arguments
length = int(length) if length and length > 1 else 30
- ddof = int(ddof) if ddof and ddof >= 0 and ddof < length else 0
+ ddof = int(ddof) if isinstance(ddof, int) and 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
close = verify_series(close, max(length, min_periods))
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import VAR
variance = VAR(close, length)
else:
@@ -54,6 +55,8 @@ def variance(close, length=None, ddof=None, offset=None, **kwargs):
ddof (int): Delta Degrees of Freedom.
The divisor used in calculations is N - ddof,
where N represents the number of elements. Default: 0
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/trend/adx.py b/pandas_ta/trend/adx.py
index aace7c2f..99063246 100644
--- a/pandas_ta/trend/adx.py
+++ b/pandas_ta/trend/adx.py
@@ -5,7 +5,7 @@
from pandas_ta.utils import get_drift, get_offset, verify_series, zero
-def adx(high, low, close, length=None, lensig=None, mamode=None, scalar=None, drift=None, offset=None, **kwargs):
+def adx(high, low, close, length=None, lensig=None, scalar=None, mamode=None, drift=None, offset=None, **kwargs):
"""Indicator: ADX"""
# Validate Arguments
length = length if length and length > 0 else 14
@@ -138,6 +138,7 @@ def adx(high, low, close, length=None, lensig=None, mamode=None, scalar=None, dr
length (int): It's period. Default: 14
lensig (int): Signal Length. Like TradingView's default ADX. Default: length
scalar (float): How much to magnify. Default: 100
+ mamode (str): See ```help(ta.ma)```. Default: 'rma'
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
diff --git a/pandas_ta/trend/amat.py b/pandas_ta/trend/amat.py
index aba60f0b..42f903bb 100644
--- a/pandas_ta/trend/amat.py
+++ b/pandas_ta/trend/amat.py
@@ -6,7 +6,7 @@
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, lookback=None, mamode=None, offset=None, **kwargs):
"""Indicator: Archer Moving Averages Trends (AMAT)"""
# Validate Arguments
fast = int(fast) if fast and fast > 0 else 8
diff --git a/pandas_ta/trend/aroon.py b/pandas_ta/trend/aroon.py
index d74317ca..9e139178 100644
--- a/pandas_ta/trend/aroon.py
+++ b/pandas_ta/trend/aroon.py
@@ -5,7 +5,7 @@
from pandas_ta.utils import recent_maximum_index, recent_minimum_index
-def aroon(high, low, length=None, scalar=None, offset=None, **kwargs):
+def aroon(high, low, length=None, scalar=None, talib=None, offset=None, **kwargs):
"""Indicator: Aroon & Aroon Oscillator"""
# Validate Arguments
length = length if length and length > 0 else 14
@@ -13,11 +13,12 @@ def aroon(high, low, length=None, scalar=None, offset=None, **kwargs):
high = verify_series(high, length)
low = verify_series(low, length)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if high is None or low is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import AROON, AROONOSC
aroon_down, aroon_up = AROON(high, low, length)
aroon_osc = AROONOSC(high, low, length)
@@ -94,6 +95,8 @@ def aroon(high, low, length=None, scalar=None, offset=None, **kwargs):
close (pd.Series): Series of 'close's
length (int): It's period. Default: 14
scalar (float): How much to magnify. Default: 100
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/trend/cksp.py b/pandas_ta/trend/cksp.py
index 36461712..ff484a18 100644
--- a/pandas_ta/trend/cksp.py
+++ b/pandas_ta/trend/cksp.py
@@ -4,7 +4,7 @@
from pandas_ta.utils import get_offset, verify_series
-def cksp(high, low, close, p=None, x=None, q=None, offset=None, tvmode=None, **kwargs):
+def cksp(high, low, close, p=None, x=None, q=None, tvmode=None, offset=None, **kwargs):
"""Indicator: Chande Kroll Stop (CKSP)"""
# Validate Arguments
# TV defaults=(10,1,9), book defaults = (10,3,20)
@@ -23,7 +23,7 @@ def cksp(high, low, close, p=None, x=None, q=None, offset=None, tvmode=None, **k
mamode = "rma" if tvmode is True else "sma"
# Calculate Result
- atr_ = atr(high=high, low=low, close=close, length=p, mamode = mamode)
+ atr_ = atr(high=high, low=low, close=close, length=p, mamode=mamode)
long_stop_ = high.rolling(p).max() - x * atr_
long_stop = long_stop_.rolling(q).max()
@@ -90,8 +90,8 @@ def cksp(high, low, close, p=None, x=None, q=None, offset=None, tvmode=None, **k
p (int): ATR and first stop period. Default: 10 in both modes
x (float): ATR scalar. Default: 1 in TV mode, 3 otherwise
q (int): Second stop period. Default: 9 in TV mode, 20 otherwise
- offset (int): How many periods to offset the result. Default: 0
tvmode (bool): Trading View or book implementation mode. Default: True
+ offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
diff --git a/pandas_ta/trend/decay.py b/pandas_ta/trend/decay.py
index f4b57fbe..65fd9689 100644
--- a/pandas_ta/trend/decay.py
+++ b/pandas_ta/trend/decay.py
@@ -63,7 +63,7 @@ def decay(close, kind=None, length=None, mode=None, offset=None, **kwargs):
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 1
- mamode (str): Option "exponential" ("exp"). Default: 'linear' or None
+ mode (str): If 'exp' then "exponential" decay. Default: 'linear'
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/trend/dpo.py b/pandas_ta/trend/dpo.py
index a3534690..91ca667e 100644
--- a/pandas_ta/trend/dpo.py
+++ b/pandas_ta/trend/dpo.py
@@ -9,6 +9,8 @@ def dpo(close, length=None, centered=True, offset=None, **kwargs):
length = int(length) if length and length > 0 else 20
close = verify_series(close, length)
offset = get_offset(offset)
+ if not kwargs.get("lookahead", True):
+ centered = False
if close is None: return
diff --git a/pandas_ta/trend/psar.py b/pandas_ta/trend/psar.py
index 5ef278ee..a3fc9c6b 100644
--- a/pandas_ta/trend/psar.py
+++ b/pandas_ta/trend/psar.py
@@ -37,7 +37,7 @@ def _falling(high, low, drift:int=1):
long = Series(npNaN, index=high.index)
short = long.copy()
- reversal = Series(False, index=high.index)
+ reversal = Series(0, index=high.index)
_af = long.copy()
_af.iloc[0:2] = af0
@@ -81,7 +81,7 @@ def _falling(high, low, drift:int=1):
long.iloc[row] = sar
_af.iloc[row] = af
- reversal.iloc[row] = reverse
+ reversal.iloc[row] = int(reverse)
# Offset
if offset != 0:
diff --git a/pandas_ta/utils/_core.py b/pandas_ta/utils/_core.py
index 14c895e3..bcb269c9 100644
--- a/pandas_ta/utils/_core.py
+++ b/pandas_ta/utils/_core.py
@@ -6,6 +6,7 @@
from numpy import argmax, argmin
from pandas import DataFrame, Series
from pandas.api.types import is_datetime64_any_dtype
+from pandas_ta import Imports
def _camelCase2Title(x: str):
@@ -82,6 +83,23 @@ def signed_series(series: Series, initial: int = None) -> Series:
return sign
+def tal_ma(name: str) -> int:
+ """Helper Function that returns the Enum value for TA Lib's MA Type"""
+ if Imports["talib"] and isinstance(name, str) and len(name) > 1:
+ from talib import MA_Type
+ name = name.lower()
+ if name == "sma": return MA_Type.SMA # 0
+ elif name == "ema": return MA_Type.EMA # 1
+ elif name == "wma": return MA_Type.WMA # 2
+ elif name == "dema": return MA_Type.DEMA # 3
+ elif name == "tema": return MA_Type.TEMA # 4
+ elif name == "trima": return MA_Type.TRIMA # 5
+ elif name == "kama": return MA_Type.KAMA # 6
+ elif name == "mama": return MA_Type.MAMA # 7
+ elif name == "t3": return MA_Type.T3 # 8
+ return 0 # Default: SMA -> 0
+
+
def unsigned_differences(series: Series, amount: int = None, **kwargs) -> Series:
"""Unsigned Differences
Returns two Series, an unsigned positive and unsigned negative series based
diff --git a/pandas_ta/utils/data/yahoofinance.py b/pandas_ta/utils/data/yahoofinance.py
index 10c37672..3fa464e2 100644
--- a/pandas_ta/utils/data/yahoofinance.py
+++ b/pandas_ta/utils/data/yahoofinance.py
@@ -87,7 +87,14 @@ def yf(ticker: str, **kwargs):
# Ticker Info & Chart History
yfd = yfra.Ticker(ticker)
- df = yfd.history(period=period, interval=interval, proxy=proxy, **kwargs)
+
+ try:
+ df = yfd.history(period=period, interval=interval, proxy=proxy, **kwargs)
+ except:
+ if yfra.__version__ == "0.1.60":
+ print(f"[!] If history is not downloading, see yfinance Issue #760 by user djl0.")
+ print(f"[!] https://github.com/ranaroussi/yfinance/issues/760#issuecomment-877355832")
+ return
if df.empty: return
df.name = ticker
diff --git a/pandas_ta/volatility/accbands.py b/pandas_ta/volatility/accbands.py
index 1ee50457..920986ba 100644
--- a/pandas_ta/volatility/accbands.py
+++ b/pandas_ta/volatility/accbands.py
@@ -93,7 +93,7 @@ def accbands(high, low, close, length=None, c=None, drift=None, mamode=None, off
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
c (int): Multiplier. Default: 4
- mamode (str): Two options: None or 'ema'. Default: 'ema'
+ mamode (str): See ```help(ta.ma)```. Default: 'sma'
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
diff --git a/pandas_ta/volatility/atr.py b/pandas_ta/volatility/atr.py
index ea861ea7..d29cf209 100644
--- a/pandas_ta/volatility/atr.py
+++ b/pandas_ta/volatility/atr.py
@@ -5,7 +5,7 @@
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, talib=None, drift=None, offset=None, **kwargs):
"""Indicator: Average True Range (ATR)"""
# Validate arguments
length = int(length) if length and length > 0 else 14
@@ -15,13 +15,14 @@ def atr(high, low, close, length=None, mamode=None, drift=None, offset=None, **k
close = verify_series(close, length)
drift = get_drift(drift)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if high is None or low is None or close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import ATR
- atr = ATR(high, low, close)
+ atr = ATR(high, low, close, length)
else:
tr = true_range(high=high, low=low, close=close, drift=drift)
atr = ma(mamode, tr, length=length)
@@ -83,7 +84,9 @@ def atr(high, low, close, length=None, mamode=None, drift=None, offset=None, **k
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
length (int): It's period. Default: 14
- mamode (str): "sma", "ema", "wma" or "rma". Default: "rma"
+ mamode (str): See ```help(ta.ma)```. Default: 'rma'
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
diff --git a/pandas_ta/volatility/bbands.py b/pandas_ta/volatility/bbands.py
index bfbc489f..e142a5ea 100644
--- a/pandas_ta/volatility/bbands.py
+++ b/pandas_ta/volatility/bbands.py
@@ -3,10 +3,10 @@
from pandas_ta import Imports
from pandas_ta.overlap import ma
from pandas_ta.statistics import stdev
-from pandas_ta.utils import get_offset, non_zero_range, verify_series
+from pandas_ta.utils import get_offset, non_zero_range, tal_ma, verify_series
-def bbands(close, length=None, std=None, mamode=None, ddof=0, offset=None, **kwargs):
+def bbands(close, length=None, std=None, ddof=0, mamode=None, talib=None, offset=None, **kwargs):
"""Indicator: Bollinger Bands (BBANDS)"""
# Validate arguments
length = int(length) if length and length > 0 else 5
@@ -15,13 +15,14 @@ def bbands(close, length=None, std=None, mamode=None, ddof=0, offset=None, **kwa
ddof = int(ddof) if ddof >= 0 and ddof < length else 1
close = verify_series(close, length)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import BBANDS
- upper, mid, lower = BBANDS(close, length)
+ upper, mid, lower = BBANDS(close, length, std, std, tal_ma(mamode))
else:
standard_deviation = stdev(close=close, length=length, ddof=ddof)
deviations = std * standard_deviation
@@ -108,8 +109,10 @@ def bbands(close, length=None, std=None, mamode=None, ddof=0, offset=None, **kwa
close (pd.Series): Series of 'close's
length (int): The short period. Default: 5
std (int): The long period. Default: 2
- mamode (str): Two options: "sma" or "ema". Default: "sma"
ddof (int): Degrees of Freedom to use. Default: 0
+ mamode (str): See ```help(ta.ma)```. Default: 'sma'
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/volatility/hwc.py b/pandas_ta/volatility/hwc.py
index e531aaeb..b539c9c0 100644
--- a/pandas_ta/volatility/hwc.py
+++ b/pandas_ta/volatility/hwc.py
@@ -85,25 +85,25 @@ def hwc(close, na=None, nb=None, nc=None, nd=None, scalar=None, channel_eval=Non
# Name and Categorize it
# suffix = f'{str(na).replace(".", "")}-{str(nb).replace(".", "")}-{str(nc).replace(".", "")}'
- hwc.name = 'HW-MID'
- hwc_upper.name = "HW-UPPER"
- hwc_lower.name = "HW-LOWER"
+ hwc.name = "HWM"
+ hwc_upper.name = "HWU"
+ hwc_lower.name = "HWL"
hwc.category = hwc_upper.category = hwc_lower.category = "volatility"
if channel_eval:
- hwc_width.name = 'HW-WIDTH'
- hwc_pctwidth.name = 'HW-PCTW'
+ hwc_width.name = "HWW"
+ hwc_pctwidth.name = "HWPCT"
# Prepare DataFrame to return
if channel_eval:
data = {hwc.name: hwc, hwc_upper.name: hwc_upper, hwc_lower.name: hwc_lower,
hwc_width.name: hwc_width, hwc_pctwidth.name: hwc_pctwidth}
df = DataFrame(data)
- df.name = "hwc"
+ df.name = "HWC"
df.category = hwc.category
else:
data = {hwc.name: hwc, hwc_upper.name: hwc_upper, hwc_lower.name: hwc_lower}
df = DataFrame(data)
- df.name = "hwc"
+ df.name = "HWC"
df.category = hwc.category
return df
@@ -149,5 +149,5 @@ def hwc(close, na=None, nb=None, nc=None, nd=None, scalar=None, channel_eval=Non
fillna (value, optional): pd.DataFrame.fillna(value)
fill_method (value, optional): Type of fill method
Returns:
- pd.DataFrame: HW-MID, HW-UPPER, HW-LOWER columns.
+ pd.DataFrame: HWM (Mid), HWU (Upper), HWL (Lower) columns.
"""
diff --git a/pandas_ta/volatility/kc.py b/pandas_ta/volatility/kc.py
index 31a81153..ba8e43c5 100644
--- a/pandas_ta/volatility/kc.py
+++ b/pandas_ta/volatility/kc.py
@@ -100,7 +100,7 @@ def kc(high, low, close, length=None, scalar=None, mamode=None, offset=None, **k
close (pd.Series): Series of 'close's
length (int): The short period. Default: 20
scalar (float): A positive float to scale the bands. Default: 2
- mamode (str): Two options: "sma" or "ema". Default: "ema"
+ mamode (str): See ```help(ta.ma)```. Default: 'ema'
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/volatility/natr.py b/pandas_ta/volatility/natr.py
index abb1de5b..be4993fa 100644
--- a/pandas_ta/volatility/natr.py
+++ b/pandas_ta/volatility/natr.py
@@ -4,7 +4,7 @@
from pandas_ta.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, scalar=None, mamode=None, talib=None, drift=None, offset=None, **kwargs):
"""Indicator: Normalized Average True Range (NATR)"""
# Validate arguments
length = int(length) if length and length > 0 else 14
@@ -15,13 +15,14 @@ def natr(high, low, close, length=None, mamode=None, scalar=None, drift=None, of
close = verify_series(close, length)
drift = get_drift(drift)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if high is None or low is None or close is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import NATR
- natr = NATR(high, low, close)
+ natr = NATR(high, low, close, length)
else:
natr = scalar / close
natr *= atr(high=high, low=low, close=close, length=length, mamode=mamode, drift=drift, offset=offset, **kwargs)
@@ -63,6 +64,9 @@ def natr(high, low, close, length=None, mamode=None, scalar=None, drift=None, of
close (pd.Series): Series of 'close's
length (int): The short period. Default: 20
scalar (float): How much to magnify. Default: 100
+ mamode (str): See ```help(ta.ma)```. Default: 'ema'
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/volatility/rvi.py b/pandas_ta/volatility/rvi.py
index 29225c29..7df65380 100644
--- a/pandas_ta/volatility/rvi.py
+++ b/pandas_ta/volatility/rvi.py
@@ -101,10 +101,10 @@ def _rvi(source, length, scalar, mode, drift):
close (pd.Series): Series of 'close's
length (int): The short period. Default: 14
scalar (float): A positive float to scale the bands. Default: 100
- mamode (str): Options: 'sma' or 'ema'. Default: 'sma'
refined (bool): Use 'refined' calculation which is the average of
RVI(high) and RVI(low) instead of RVI(close). Default: False
thirds (bool): Average of high, low and close. Default: False
+ mamode (str): See ```help(ta.ma)```. Default: 'ema'
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/volatility/thermo.py b/pandas_ta/volatility/thermo.py
index d1e539e7..b628033e 100644
--- a/pandas_ta/volatility/thermo.py
+++ b/pandas_ta/volatility/thermo.py
@@ -112,8 +112,8 @@ def thermo(high, low, length=None, long=None, short=None, mamode=None, drift=Non
long(int): The buy factor
short(float): The sell factor
length (int): The period. Default: 20
+ mamode (str): See ```help(ta.ma)```. Default: 'ema'
drift (int): The diff period. Default: 1
- mamode (str): Three options: "ema", "sma", or "hma". Default: "ema"
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/volatility/true_range.py b/pandas_ta/volatility/true_range.py
index 687b6307..f2c0331e 100644
--- a/pandas_ta/volatility/true_range.py
+++ b/pandas_ta/volatility/true_range.py
@@ -5,7 +5,7 @@
from pandas_ta.utils import get_drift, get_offset, non_zero_range, verify_series
-def true_range(high, low, close, drift=None, offset=None, **kwargs):
+def true_range(high, low, close, talib=None, drift=None, offset=None, **kwargs):
"""Indicator: True Range"""
# Validate arguments
high = verify_series(high)
@@ -13,9 +13,10 @@ def true_range(high, low, close, drift=None, offset=None, **kwargs):
close = verify_series(close)
drift = get_drift(drift)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import TRANGE
true_range = TRANGE(high, low, close)
else:
@@ -63,6 +64,8 @@ def true_range(high, low, close, drift=None, offset=None, **kwargs):
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
drift (int): The shift period. Default: 1
offset (int): How many periods to offset the result. Default: 0
diff --git a/pandas_ta/volume/ad.py b/pandas_ta/volume/ad.py
index 557acdea..4c0e9755 100644
--- a/pandas_ta/volume/ad.py
+++ b/pandas_ta/volume/ad.py
@@ -3,7 +3,7 @@
from pandas_ta.utils import get_offset, non_zero_range, verify_series
-def ad(high, low, close, volume, open_=None, offset=None, **kwargs):
+def ad(high, low, close, volume, open_=None, talib=None, offset=None, **kwargs):
"""Indicator: Accumulation/Distribution (AD)"""
# Validate Arguments
high = verify_series(high)
@@ -11,9 +11,10 @@ def ad(high, low, close, volume, open_=None, offset=None, **kwargs):
close = verify_series(close)
volume = verify_series(volume)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import AD
ad = AD(high, low, close, volume)
else:
@@ -70,6 +71,8 @@ def ad(high, low, close, volume, open_=None, offset=None, **kwargs):
close (pd.Series): Series of 'close's
volume (pd.Series): Series of 'volume's
open (pd.Series): Series of 'open's
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/volume/adosc.py b/pandas_ta/volume/adosc.py
index 0f1ddca5..b315579b 100644
--- a/pandas_ta/volume/adosc.py
+++ b/pandas_ta/volume/adosc.py
@@ -5,7 +5,7 @@
from pandas_ta.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, talib=None, offset=None, **kwargs):
"""Indicator: Accumulation/Distribution Oscillator"""
# Validate Arguments
fast = int(fast) if fast and fast > 0 else 3
@@ -17,13 +17,14 @@ def adosc(high, low, close, volume, open_=None, fast=None, slow=None, offset=Non
volume = verify_series(volume, _length)
offset = get_offset(offset)
if "length" in kwargs: kwargs.pop("length")
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if high is None or low is None or close is None or volume is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import ADOSC
- adosc = ADOSC(high, low, close, volume)
+ adosc = ADOSC(high, low, close, volume, fast, slow)
else:
ad_ = ad(high=high, low=low, close=close, volume=volume, open_=open_)
fast_ad = ema(close=ad_, length=fast, **kwargs)
@@ -74,6 +75,8 @@ def adosc(high, low, close, volume, open_=None, fast=None, slow=None, offset=Non
volume (pd.Series): Series of 'volume's
fast (int): The short period. Default: 12
slow (int): The long period. Default: 26
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/volume/aobv.py b/pandas_ta/volume/aobv.py
index a2c06990..70c3539c 100644
--- a/pandas_ta/volume/aobv.py
+++ b/pandas_ta/volume/aobv.py
@@ -6,7 +6,7 @@
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, max_lookback=None, min_lookback=None, mamode=None, offset=None, **kwargs):
"""Indicator: Archer On Balance Volume (AOBV)"""
# Validate arguments
fast = int(fast) if fast and fast > 0 else 4
diff --git a/pandas_ta/volume/efi.py b/pandas_ta/volume/efi.py
index 63643456..79d567ed 100644
--- a/pandas_ta/volume/efi.py
+++ b/pandas_ta/volume/efi.py
@@ -3,7 +3,7 @@
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, mamode=None, drift=None, offset=None, **kwargs):
"""Indicator: Elder's Force Index (EFI)"""
# Validate arguments
length = int(length) if length and length > 0 else 13
@@ -63,7 +63,7 @@ def efi(close, volume, length=None, drift=None, mamode=None, offset=None, **kwar
volume (pd.Series): Series of 'volume's
length (int): The short period. Default: 13
drift (int): The diff period. Default: 1
- mamode (str): Two options: None or "sma". Default: None
+ mamode (str): See ```help(ta.ma)```. Default: 'ema'
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/volume/kvo.py b/pandas_ta/volume/kvo.py
index a497a02a..927dd048 100644
--- a/pandas_ta/volume/kvo.py
+++ b/pandas_ta/volume/kvo.py
@@ -1,18 +1,17 @@
# -*- coding: utf-8 -*-
-from numpy import where as npWhere
from pandas import DataFrame
from pandas_ta.overlap import hlc3, ma
-from pandas_ta.utils import get_drift, get_offset, non_zero_range, verify_series
+from pandas_ta.utils import get_drift, get_offset, signed_series, verify_series
-def kvo(high, low, close, volume, fast=None, slow=None, length_sig=None, mamode=None, drift=None, offset=None, **kwargs):
+def kvo(high, low, close, volume, fast=None, slow=None, signal=None, mamode=None, drift=None, offset=None, **kwargs):
"""Indicator: Klinger Volume Oscillator (KVO)"""
# Validate arguments
fast = int(fast) if fast and fast > 0 else 34
slow = int(slow) if slow and slow > 0 else 55
- length_sig = int(length_sig) if length_sig and length_sig > 0 else 13
+ signal = int(signal) if signal and signal > 0 else 13
mamode = mamode.lower() if mamode and isinstance(mamode, str) else "ema"
- _length = max(fast, slow, length_sig)
+ _length = max(fast, slow, signal)
high = verify_series(high, _length)
low = verify_series(low, _length)
close = verify_series(close, _length)
@@ -23,19 +22,10 @@ def kvo(high, low, close, volume, fast=None, slow=None, length_sig=None, mamode=
if high is None or low is None or close is None or volume is None: return
# Calculate Result
- mom = hlc3(high, low, close).diff(drift)
- trend = npWhere(mom > 0, 1, 0) + npWhere(mom < 0, -1, 0)
- dm = non_zero_range(high, low)
-
- m = high.size
- cm = [0] * m
- for i in range(1, m):
- cm[i] = (cm[i - 1] + dm[i]) if trend[i] == trend[i - 1] else (dm[i - 1] + dm[i])
-
- vf = 100 * volume * trend * abs(2 * dm / cm - 1)
-
- kvo = ma(mamode, vf, length=fast) - ma(mamode, vf, length=slow)
- kvo_signal = ma(mamode, kvo, length=length_sig)
+ signed_volume = volume * signed_series(hlc3(high, low, close), 1)
+ sv = signed_volume.loc[signed_volume.first_valid_index():,]
+ kvo = ma(mamode, sv, length=fast) - ma(mamode, sv, length=slow)
+ kvo_signal = ma(mamode, kvo.loc[kvo.first_valid_index():,], length=signal)
# Offset
if offset != 0:
@@ -51,17 +41,18 @@ def kvo(high, low, close, volume, fast=None, slow=None, length_sig=None, mamode=
kvo_signal.fillna(method=kwargs["fill_method"], inplace=True)
# Name and Categorize it
- kvo.name = f"KVO_{fast}_{slow}"
- kvo_signal.name = f"KVOSig_{length_sig}"
+ _props = f"_{fast}_{slow}_{signal}"
+ kvo.name = f"KVO{_props}"
+ kvo_signal.name = f"KVOs{_props}"
kvo.category = kvo_signal.category = "volume"
# Prepare DataFrame to return
data = {kvo.name: kvo, kvo_signal.name: kvo_signal}
- kvoandsig = DataFrame(data)
- kvoandsig.name = f"KVO_{fast}_{slow}_{length_sig}"
- kvoandsig.category = kvo.category
+ df = DataFrame(data)
+ df.name = f"KVO{_props}"
+ df.category = kvo.category
- return kvoandsig
+ return df
kvo.__doc__ = \
@@ -71,23 +62,17 @@ def kvo(high, low, close, volume, fast=None, slow=None, length_sig=None, mamode=
price reversals in a market by comparing volume to price.
Sources:
- https://www.tradingview.com/script/Qnn7ymRK-Klinger-Volume-Oscillator/
+ https://www.investopedia.com/terms/k/klingeroscillator.asp
https://www.daytrading.com/klinger-volume-oscillator
Calculation:
Default Inputs:
- fast=34, slow=55, length_sig=13, drift=1
- MOM = HLC3.diff(drift)
- NEG_TREND = -1 if MOM < 0 else 0
- POS_TREND = 1 if MOM > 0 else 0
- TREND = POS_TREND + NEG_TREND
- DM = high - low
- CM = [CMt-1 + DMt if TRENDt == TRENDt-1 else DMt-1 + DMt]
-
- vf = 100 * volume * TREND * abs(2 * dm / cm - 1)
- kvo = ema(vf, fast) - ema(vf, slow)
- kvo_signal = ema(kvo, length_sig)
+ fast=34, slow=55, signal=13, drift=1
+ EMA = Exponential Moving Average
+ SV = volume * signed_series(HLC3, 1)
+ KVO = EMA(SV, fast) - EMA(SV, slow)
+ Signal = EMA(KVO, signal)
Args:
high (pd.Series): Series of 'high's
@@ -97,7 +82,7 @@ def kvo(high, low, close, volume, fast=None, slow=None, length_sig=None, mamode=
fast (int): The fast period. Default: 34
long (int): The long period. Default: 55
length_sig (int): The signal period. Default: 13
- mamode (str): "sma", "ema", "wma" or "rma". Default: "ema"
+ mamode (str): See ```help(ta.ma)```. Default: 'ema'
offset (int): How many periods to offset the result. Default: 0
Kwargs:
@@ -105,5 +90,5 @@ def kvo(high, low, close, volume, fast=None, slow=None, length_sig=None, mamode=
fill_method (value, optional): Type of fill method
Returns:
- pd.DataFrame: kvo and kvo_signal columns.
+ pd.DataFrame: KVO and Signal columns.
"""
diff --git a/pandas_ta/volume/mfi.py b/pandas_ta/volume/mfi.py
index 72c93131..1363b00a 100644
--- a/pandas_ta/volume/mfi.py
+++ b/pandas_ta/volume/mfi.py
@@ -5,7 +5,7 @@
from pandas_ta.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, talib=None, drift=None, offset=None, **kwargs):
"""Indicator: Money Flow Index (MFI)"""
# Validate arguments
length = int(length) if length and length > 0 else 14
@@ -15,13 +15,14 @@ def mfi(high, low, close, volume, length=None, drift=None, offset=None, **kwargs
volume = verify_series(volume, length)
drift = get_drift(drift)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
if high is None or low is None or close is None or volume is None: return
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import MFI
- mfi = MFI(high, low, close, volume)
+ mfi = MFI(high, low, close, volume, length)
else:
typical_price = hlc3(high=high, low=low, close=close)
raw_money_flow = typical_price * volume
@@ -84,6 +85,8 @@ def mfi(high, low, close, volume, length=None, drift=None, offset=None, **kwargs
close (pd.Series): Series of 'close's
volume (pd.Series): Series of 'volume's
length (int): The sum period. Default: 14
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
diff --git a/pandas_ta/volume/nvi.py b/pandas_ta/volume/nvi.py
index fb08b318..1c1ceadb 100644
--- a/pandas_ta/volume/nvi.py
+++ b/pandas_ta/volume/nvi.py
@@ -17,7 +17,7 @@ def nvi(close, volume, length=None, initial=None, offset=None, **kwargs):
# Calculate Result
roc_ = roc(close=close, length=length)
- signed_volume = signed_series(volume, initial=1)
+ signed_volume = signed_series(volume, 1)
nvi = signed_volume[signed_volume < 0].abs() * roc_
nvi.fillna(0, inplace=True)
nvi.iloc[0] = initial
diff --git a/pandas_ta/volume/obv.py b/pandas_ta/volume/obv.py
index 539b09b8..ec15be17 100644
--- a/pandas_ta/volume/obv.py
+++ b/pandas_ta/volume/obv.py
@@ -3,15 +3,16 @@
from pandas_ta.utils import get_offset, signed_series, verify_series
-def obv(close, volume, offset=None, **kwargs):
+def obv(close, volume, talib=None, offset=None, **kwargs):
"""Indicator: On Balance Volume (OBV)"""
# Validate arguments
close = verify_series(close)
volume = verify_series(volume)
offset = get_offset(offset)
+ mode_tal = bool(talib) if isinstance(talib, bool) else True
# Calculate Result
- if Imports["talib"]:
+ if Imports["talib"] and mode_tal:
from talib import OBV
obv = OBV(close, volume)
else:
@@ -53,6 +54,8 @@ def obv(close, volume, offset=None, **kwargs):
Args:
close (pd.Series): Series of 'close's
volume (pd.Series): Series of 'volume's
+ talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
+ version. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
diff --git a/pandas_ta/volume/pvi.py b/pandas_ta/volume/pvi.py
index 8ab2da91..302d378e 100644
--- a/pandas_ta/volume/pvi.py
+++ b/pandas_ta/volume/pvi.py
@@ -16,9 +16,8 @@ def pvi(close, volume, length=None, initial=None, offset=None, **kwargs):
if close is None or volume is None: return
# Calculate Result
- roc_ = roc(close=close, length=length)
- signed_volume = signed_series(volume, initial=1)
- pvi = signed_volume[signed_volume > 0].abs() * roc_
+ signed_volume = signed_series(volume, 1)
+ pvi = roc(close=close, length=length) * signed_volume[signed_volume > 0].abs()
pvi.fillna(0, inplace=True)
pvi.iloc[0] = initial
pvi = pvi.cumsum()
diff --git a/pandas_ta/volume/pvol.py b/pandas_ta/volume/pvol.py
index 8168943d..aba68324 100644
--- a/pandas_ta/volume/pvol.py
+++ b/pandas_ta/volume/pvol.py
@@ -11,10 +11,9 @@ def pvol(close, volume, offset=None, **kwargs):
signed = kwargs.pop("signed", False)
# Calculate Result
+ pvol = close * volume
if signed:
- pvol = signed_series(close, 1) * close * volume
- else:
- pvol = close * volume
+ pvol *= signed_series(close, 1)
# Offset
if offset != 0:
diff --git a/pandas_ta/volume/vp.py b/pandas_ta/volume/vp.py
index b6f52735..7a5d7cef 100644
--- a/pandas_ta/volume/vp.py
+++ b/pandas_ta/volume/vp.py
@@ -16,10 +16,10 @@ def vp(close, volume, width=None, **kwargs):
if close is None or volume is None: return
# Setup
- signed_price = signed_series(close, initial=1)
- pos_volume = signed_price[signed_price > 0] * volume
+ signed_price = signed_series(close, 1)
+ pos_volume = volume * signed_price[signed_price > 0]
pos_volume.name = volume.name
- neg_volume = signed_price[signed_price < 0] * -volume
+ neg_volume = -volume * signed_price[signed_price < 0]
neg_volume.name = volume.name
vp = concat([close, pos_volume, neg_volume], axis=1)
diff --git a/requirements.txt b/requirements.txt
index 21c37a1f..74f7aec7 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,5 @@
-numpy>=1.20.2
-pandas>=1.2.4
\ No newline at end of file
+numpy==1.19.5
+pandas==1.2.0
+python-dateutil==2.8.1
+pytz==2021.1
+six==1.16.0
diff --git a/setup.py b/setup.py
index 0837bedf..0dc65944 100644
--- a/setup.py
+++ b/setup.py
@@ -19,7 +19,7 @@
"pandas_ta.volatility",
"pandas_ta.volume"
],
- version=".".join(("0", "3", "02b")),
+ version=".".join(("0", "3", "14b")),
description=long_description,
long_description=long_description,
author="Kevin Johnson",
diff --git a/tests/test_ext_indicator_candle.py b/tests/test_ext_indicator_candle.py
index 787040c0..55ba9d70 100644
--- a/tests/test_ext_indicator_candle.py
+++ b/tests/test_ext_indicator_candle.py
@@ -1,7 +1,7 @@
from .config import sample_data
from .context import pandas_ta
-from unittest import TestCase
+from unittest import TestCase, skip
from pandas import DataFrame
@@ -17,7 +17,6 @@ def tearDownClass(cls):
def setUp(self): pass
def tearDown(self): pass
-
def test_cdl_doji_ext(self):
self.data.ta.cdl_pattern("doji", append=True)
self.assertIsInstance(self.data, DataFrame)
diff --git a/tests/test_ext_indicator_momentum.py b/tests/test_ext_indicator_momentum.py
index e8e8c01d..fee7d091 100644
--- a/tests/test_ext_indicator_momentum.py
+++ b/tests/test_ext_indicator_momentum.py
@@ -247,7 +247,7 @@ def test_trix_ext(self):
def test_tsi_ext(self):
self.data.ta.tsi(append=True)
self.assertIsInstance(self.data, DataFrame)
- self.assertEqual(self.data.columns[-1], "TSI_13_25")
+ self.assertEqual(list(self.data.columns[-2:]), ["TSI_13_25_13", "TSIs_13_25_13"])
def test_uo_ext(self):
self.data.ta.uo(append=True)
diff --git a/tests/test_ext_indicator_overlap_ext.py b/tests/test_ext_indicator_overlap_ext.py
index f56ba411..e6bdebc5 100644
--- a/tests/test_ext_indicator_overlap_ext.py
+++ b/tests/test_ext_indicator_overlap_ext.py
@@ -63,6 +63,11 @@ def test_hwma_ext(self):
self.assertIsInstance(self.data, DataFrame)
self.assertEqual(self.data.columns[-1], "HWMA_0.2_0.1_0.1")
+ def test_jma_ext(self):
+ self.data.ta.jma(append=True)
+ self.assertIsInstance(self.data, DataFrame)
+ self.assertEqual(self.data.columns[-1], "JMA_7_0")
+
def test_kama_ext(self):
self.data.ta.kama(append=True)
self.assertIsInstance(self.data, DataFrame)
diff --git a/tests/test_ext_indicator_volume.py b/tests/test_ext_indicator_volume.py
index a95292ce..1ca417ec 100644
--- a/tests/test_ext_indicator_volume.py
+++ b/tests/test_ext_indicator_volume.py
@@ -63,7 +63,7 @@ def test_eom_ext(self):
def test_kvo_ext(self):
self.data.ta.kvo(append=True)
self.assertIsInstance(self.data, DataFrame)
- self.assertEqual(self.data.columns[-1], "KVOSig_13")
+ self.assertEqual(list(self.data.columns[-2:]), ["KVO_34_55_13", "KVOs_34_55_13"])
def test_mfi_ext(self):
self.data.ta.mfi(append=True)
diff --git a/tests/test_indicator_candle.py b/tests/test_indicator_candle.py
index 083ef67f..619bc6e2 100644
--- a/tests/test_indicator_candle.py
+++ b/tests/test_indicator_candle.py
@@ -58,7 +58,7 @@ def test_cdl_doji(self):
try:
expected = tal.CDLDOJI(self.open, self.high, self.low, self.close)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
corr = pandas_ta.utils.df_error_analysis(result, expected, col=CORRELATION)
self.assertGreater(corr, CORRELATION_THRESHOLD)
diff --git a/tests/test_indicator_momentum.py b/tests/test_indicator_momentum.py
index 84e4b689..a11e7872 100644
--- a/tests/test_indicator_momentum.py
+++ b/tests/test_indicator_momentum.py
@@ -65,60 +65,72 @@ def test_ao(self):
self.assertEqual(result.name, "AO_5_34")
def test_apo(self):
- result = pandas_ta.apo(self.close)
+ result = pandas_ta.apo(self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "APO_12_26")
try:
expected = tal.APO(self.close)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.apo(self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "APO_12_26")
+
def test_bias(self):
result = pandas_ta.bias(self.close)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "BIAS_SMA_26")
def test_bop(self):
- result = pandas_ta.bop(self.open, self.high, self.low, self.close)
+ result = pandas_ta.bop(self.open, self.high, self.low, self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "BOP")
try:
expected = tal.BOP(self.open, self.high, self.low, self.close)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.bop(self.open, self.high, self.low, self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "BOP")
+
def test_brar(self):
result = pandas_ta.brar(self.open, self.high, self.low, self.close)
self.assertIsInstance(result, DataFrame)
self.assertEqual(result.name, "BRAR_26")
def test_cci(self):
- result = pandas_ta.cci(self.high, self.low, self.close)
+ result = pandas_ta.cci(self.high, self.low, self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "CCI_14_0.015")
try:
expected = tal.CCI(self.high, self.low, self.close)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.cci(self.high, self.low, self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "CCI_14_0.015")
+
def test_cfo(self):
result = pandas_ta.cfo(self.close)
self.assertIsInstance(result, Series)
@@ -137,13 +149,17 @@ def test_cmo(self):
try:
expected = tal.CMO(self.close)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.cmo(self.close, talib=False)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "CMO_14")
+
def test_coppock(self):
result = pandas_ta.coppock(self.close)
self.assertIsInstance(result, Series)
@@ -160,7 +176,7 @@ def test_er(self):
self.assertEqual(result.name, "ER_10")
def test_dm(self):
- result = pandas_ta.dm(self.high, self.low)
+ result = pandas_ta.dm(self.high, self.low, talib=False)
self.assertIsInstance(result, DataFrame)
self.assertEqual(result.name, "DM_14")
@@ -169,7 +185,7 @@ def test_dm(self):
expected_neg = tal.MINUS_DM(self.high, self.low)
expecteddf = DataFrame({"DMP_14": expected_pos, "DMN_14": expected_neg})
pdt.assert_frame_equal(result, expecteddf)
- except AssertionError as ae:
+ except AssertionError:
try:
dmp = pandas_ta.utils.df_error_analysis(result.iloc[:,0], expecteddf.iloc[:,0], col=CORRELATION)
self.assertGreater(dmp, CORRELATION_THRESHOLD)
@@ -182,6 +198,10 @@ def test_dm(self):
except Exception as ex:
error_analysis(result, CORRELATION, ex)
+ result = pandas_ta.dm(self.high, self.low)
+ self.assertIsInstance(result, DataFrame)
+ self.assertEqual(result.name, "DM_14")
+
def test_eri(self):
result = pandas_ta.eri(self.high, self.low, self.close)
self.assertIsInstance(result, DataFrame)
@@ -216,7 +236,7 @@ def test_kst(self):
self.assertEqual(result.name, "KST_10_15_20_30_10_10_10_15_9")
def test_macd(self):
- result = pandas_ta.macd(self.close)
+ result = pandas_ta.macd(self.close, talib=False)
self.assertIsInstance(result, DataFrame)
self.assertEqual(result.name, "MACD_12_26_9")
@@ -224,7 +244,7 @@ def test_macd(self):
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]})
pdt.assert_frame_equal(result, expecteddf)
- except AssertionError as ae:
+ except AssertionError:
try:
macd_corr = pandas_ta.utils.df_error_analysis(result.iloc[:, 0], expecteddf.iloc[:, 0], col=CORRELATION)
self.assertGreater(macd_corr, CORRELATION_THRESHOLD)
@@ -243,41 +263,58 @@ def test_macd(self):
except Exception as ex:
error_analysis(result.iloc[:, 2], CORRELATION, ex, newline=False)
+ result = pandas_ta.macd(self.close)
+ self.assertIsInstance(result, DataFrame)
+ self.assertEqual(result.name, "MACD_12_26_9")
+
+ def test_macdas(self):
+ result = pandas_ta.macd(self.close, asmode=True)
+ self.assertIsInstance(result, DataFrame)
+ self.assertEqual(result.name, "MACDAS_12_26_9")
+
def test_mom(self):
- result = pandas_ta.mom(self.close)
+ result = pandas_ta.mom(self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "MOM_10")
try:
expected = tal.MOM(self.close)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.mom(self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "MOM_10")
+
def test_pgo(self):
result = pandas_ta.pgo(self.high, self.low, self.close)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "PGO_14")
def test_ppo(self):
- result = pandas_ta.ppo(self.close)
+ result = pandas_ta.ppo(self.close, talib=False)
self.assertIsInstance(result, DataFrame)
self.assertEqual(result.name, "PPO_12_26_9")
try:
expected = tal.PPO(self.close)
pdt.assert_series_equal(result["PPO_12_26_9"], expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.ppo(self.close)
+ self.assertIsInstance(result, DataFrame)
+ self.assertEqual(result.name, "PPO_12_26_9")
+
def test_psl(self):
result = pandas_ta.psl(self.close)
self.assertIsInstance(result, Series)
@@ -294,35 +331,43 @@ def test_qqe(self):
self.assertEqual(result.name, "QQE_14_5_4.236")
def test_roc(self):
- result = pandas_ta.roc(self.close)
+ result = pandas_ta.roc(self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "ROC_10")
try:
expected = tal.ROC(self.close)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.roc(self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "ROC_10")
+
def test_rsi(self):
- result = pandas_ta.rsi(self.close)
+ result = pandas_ta.rsi(self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "RSI_14")
try:
expected = tal.RSI(self.close)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.rsi(self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "RSI_14")
+
def test_rsx(self):
result = pandas_ta.rsx(self.close)
self.assertIsInstance(result, Series)
@@ -406,10 +451,10 @@ def test_stoch(self):
self.assertEqual(result.name, "STOCH_14_3_3")
try:
- expected = tal.STOCH(self.high, self.low, self.close, 14, 3, 0, 3)
- expecteddf = DataFrame({"STOCHk_14_3_0_3": expected[0], "STOCHd_14_3_0_3": expected[1]})
+ expected = tal.STOCH(self.high, self.low, self.close, 14, 3, 0, 3, 0)
+ expecteddf = DataFrame({"STOCHk_14_3_0_3_0": expected[0], "STOCHd_14_3_0_3": expected[1]})
pdt.assert_frame_equal(result, expecteddf)
- except AssertionError as ae:
+ except AssertionError:
try:
stochk_corr = pandas_ta.utils.df_error_analysis(result.iloc[:, 0], expecteddf.iloc[:, 0], col=CORRELATION)
self.assertGreater(stochk_corr, CORRELATION_THRESHOLD)
@@ -432,7 +477,7 @@ def test_stochrsi(self):
expected = tal.STOCHRSI(self.close, 14, 14, 3, 0)
expecteddf = DataFrame({"STOCHRSIk_14_14_0_3": expected[0], "STOCHRSId_14_14_3_0": expected[1]})
pdt.assert_frame_equal(result, expecteddf)
- except AssertionError as ae:
+ except AssertionError:
try:
stochrsid_corr = pandas_ta.utils.df_error_analysis(result.iloc[:, 0], expecteddf.iloc[:, 1], col=CORRELATION)
self.assertGreater(stochrsid_corr, CORRELATION_THRESHOLD)
@@ -453,35 +498,43 @@ def test_trix(self):
def test_tsi(self):
result = pandas_ta.tsi(self.close)
- self.assertIsInstance(result, Series)
- self.assertEqual(result.name, "TSI_13_25")
+ self.assertIsInstance(result, DataFrame)
+ self.assertEqual(result.name, "TSI_13_25_13")
def test_uo(self):
- result = pandas_ta.uo(self.high, self.low, self.close)
+ result = pandas_ta.uo(self.high, self.low, self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "UO_7_14_28")
try:
expected = tal.ULTOSC(self.high, self.low, self.close)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.uo(self.high, self.low, self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "UO_7_14_28")
+
def test_willr(self):
- result = pandas_ta.willr(self.high, self.low, self.close)
+ result = pandas_ta.willr(self.high, self.low, self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "WILLR_14")
try:
expected = tal.WILLR(self.high, self.low, self.close)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+
+ result = pandas_ta.willr(self.high, self.low, self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "WILLR_14")
diff --git a/tests/test_indicator_overlap.py b/tests/test_indicator_overlap.py
index b8bf9dc3..58489697 100644
--- a/tests/test_indicator_overlap.py
+++ b/tests/test_indicator_overlap.py
@@ -40,20 +40,24 @@ def test_alma(self):
self.assertEqual(result.name, "ALMA_10_6.0_0.85")
def test_dema(self):
- result = pandas_ta.dema(self.close)
+ result = pandas_ta.dema(self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "DEMA_10")
try:
expected = tal.DEMA(self.close, 10)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.dema(self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "DEMA_10")
+
def test_ema(self):
result = pandas_ta.ema(self.close, presma=False)
self.assertIsInstance(result, Series)
@@ -62,13 +66,30 @@ def test_ema(self):
try:
expected = tal.EMA(self.close, 10)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
+ try:
+ 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)
+
+ result = pandas_ta.ema(self.close, talib=False)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "EMA_10")
+
+ try:
+ pdt.assert_series_equal(result, expected, check_names=False)
+ except AssertionError:
try:
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)
+ result = pandas_ta.ema(self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "EMA_10")
+
def test_fwma(self):
result = pandas_ta.fwma(self.close)
self.assertIsInstance(result, Series)
@@ -85,20 +106,24 @@ def test_hl2(self):
self.assertEqual(result.name, "HL2")
def test_hlc3(self):
- result = pandas_ta.hlc3(self.high, self.low, self.close)
+ result = pandas_ta.hlc3(self.high, self.low, self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "HLC3")
try:
expected = tal.TYPPRICE(self.high, self.low, self.close)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.hlc3(self.high, self.low, self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "HLC3")
+
def test_hma(self):
result = pandas_ta.hma(self.close)
self.assertIsInstance(result, Series)
@@ -114,6 +139,11 @@ def test_kama(self):
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "KAMA_10_2_30")
+ def test_jma(self):
+ result = pandas_ta.jma(self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "JMA_7_0")
+
def test_ichimoku(self):
ichimoku, span = pandas_ta.ichimoku(self.high, self.low, self.close)
self.assertIsInstance(ichimoku, DataFrame)
@@ -122,70 +152,86 @@ def test_ichimoku(self):
self.assertEqual(span.name, "ICHISPAN_9_26")
def test_linreg(self):
- result = pandas_ta.linreg(self.close)
+ result = pandas_ta.linreg(self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "LR_14")
try:
expected = tal.LINEARREG(self.close)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.linreg(self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "LR_14")
+
def test_linreg_angle(self):
- result = pandas_ta.linreg(self.close, angle=True)
+ result = pandas_ta.linreg(self.close, angle=True, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "LRa_14")
try:
expected = tal.LINEARREG_ANGLE(self.close)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.linreg(self.close, angle=True)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "LRa_14")
+
def test_linreg_intercept(self):
- result = pandas_ta.linreg(self.close, intercept=True)
+ result = pandas_ta.linreg(self.close, intercept=True, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "LRb_14")
try:
expected = tal.LINEARREG_INTERCEPT(self.close)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.linreg(self.close, intercept=True)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "LRb_14")
+
def test_linreg_r(self):
result = pandas_ta.linreg(self.close, r=True)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "LRr_14")
def test_linreg_slope(self):
- result = pandas_ta.linreg(self.close, slope=True)
+ result = pandas_ta.linreg(self.close, slope=True, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "LRm_14")
try:
expected = tal.LINEARREG_SLOPE(self.close)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.linreg(self.close, slope=True)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "LRm_14")
+
def test_ma(self):
result = pandas_ta.ma()
self.assertIsInstance(result, list)
@@ -205,35 +251,43 @@ def test_mcgd(self):
self.assertEqual(result.name, "MCGD_10")
def test_midpoint(self):
- result = pandas_ta.midpoint(self.close)
+ result = pandas_ta.midpoint(self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "MIDPOINT_2")
try:
expected = tal.MIDPOINT(self.close, 2)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.midpoint(self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "MIDPOINT_2")
+
def test_midprice(self):
- result = pandas_ta.midprice(self.high, self.low)
+ result = pandas_ta.midprice(self.high, self.low, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "MIDPRICE_2")
try:
expected = tal.MIDPRICE(self.high, self.low, 2)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.midprice(self.high, self.low)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "MIDPRICE_2")
+
def test_ohlc4(self):
result = pandas_ta.ohlc4(self.open, self.high, self.low, self.close)
self.assertIsInstance(result, Series)
@@ -255,20 +309,24 @@ def test_sinwma(self):
self.assertEqual(result.name, "SINWMA_14")
def test_sma(self):
- result = pandas_ta.sma(self.close)
+ result = pandas_ta.sma(self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "SMA_10")
try:
expected = tal.SMA(self.close, 10)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.sma(self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "SMA_10")
+
def test_ssf(self):
result = pandas_ta.ssf(self.close, poles=2)
self.assertIsInstance(result, Series)
@@ -289,50 +347,62 @@ def test_supertrend(self):
self.assertEqual(result.name, "SUPERT_7_3.0")
def test_t3(self):
- result = pandas_ta.t3(self.close)
+ result = pandas_ta.t3(self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "T3_10_0.7")
try:
expected = tal.T3(self.close, 10)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.t3(self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "T3_10_0.7")
+
def test_tema(self):
- result = pandas_ta.tema(self.close)
+ result = pandas_ta.tema(self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "TEMA_10")
try:
expected = tal.TEMA(self.close, 10)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.tema(self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "TEMA_10")
+
def test_trima(self):
- result = pandas_ta.trima(self.close)
+ result = pandas_ta.trima(self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "TRIMA_10")
try:
expected = tal.TRIMA(self.close, 10)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.trima(self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "TRIMA_10")
+
def test_vidya(self):
result = pandas_ta.vidya(self.close)
self.assertIsInstance(result, Series)
@@ -349,35 +419,43 @@ def test_vwma(self):
self.assertEqual(result.name, "VWMA_10")
def test_wcp(self):
- result = pandas_ta.wcp(self.high, self.low, self.close)
+ result = pandas_ta.wcp(self.high, self.low, self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "WCP")
try:
expected = tal.WCLPRICE(self.high, self.low, self.close)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.wcp(self.high, self.low, self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "WCP")
+
def test_wma(self):
- result = pandas_ta.wma(self.close)
+ result = pandas_ta.wma(self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "WMA_10")
try:
expected = tal.WMA(self.close, 10)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.wma(self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "WMA_10")
+
def test_zlma(self):
result = pandas_ta.zlma(self.close)
self.assertIsInstance(result, Series)
diff --git a/tests/test_indicator_statistics.py b/tests/test_indicator_statistics.py
index d580a5c2..b572b570 100644
--- a/tests/test_indicator_statistics.py
+++ b/tests/test_indicator_statistics.py
@@ -65,20 +65,24 @@ def test_skew(self):
self.assertEqual(result.name, "SKEW_30")
def test_stdev(self):
- result = pandas_ta.stdev(self.close)
+ result = pandas_ta.stdev(self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "STDEV_30")
try:
expected = tal.STDDEV(self.close, 30)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.stdev(self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "STDEV_30")
+
def test_tos_sdtevall(self):
result = pandas_ta.tos_stdevall(self.close)
self.assertIsInstance(result, DataFrame)
@@ -96,20 +100,24 @@ def test_tos_sdtevall(self):
self.assertEqual(len(result.columns), 5)
def test_variance(self):
- result = pandas_ta.variance(self.close)
+ result = pandas_ta.variance(self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "VAR_30")
try:
expected = tal.VAR(self.close, 30)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.variance(self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "VAR_30")
+
def test_zscore(self):
result = pandas_ta.zscore(self.close)
self.assertIsInstance(result, Series)
diff --git a/tests/test_indicator_trend.py b/tests/test_indicator_trend.py
index 85419347..cf01c733 100644
--- a/tests/test_indicator_trend.py
+++ b/tests/test_indicator_trend.py
@@ -35,27 +35,31 @@ def tearDown(self): pass
def test_adx(self):
- result = pandas_ta.adx(self.high, self.low, self.close)
+ result = pandas_ta.adx(self.high, self.low, self.close, talib=False)
self.assertIsInstance(result, DataFrame)
self.assertEqual(result.name, "ADX_14")
try:
expected = tal.ADX(self.high, self.low, self.close)
pdt.assert_series_equal(result.iloc[:, 0], expected)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.adx(self.high, self.low, self.close)
+ self.assertIsInstance(result, DataFrame)
+ self.assertEqual(result.name, "ADX_14")
+
def test_amat(self):
result = pandas_ta.amat(self.close)
self.assertIsInstance(result, DataFrame)
self.assertEqual(result.name, "AMATe_8_21_2")
def test_aroon(self):
- result = pandas_ta.aroon(self.high, self.low)
+ result = pandas_ta.aroon(self.high, self.low, talib=False)
self.assertIsInstance(result, DataFrame)
self.assertEqual(result.name, "AROON_14")
@@ -63,7 +67,7 @@ def test_aroon(self):
expected = tal.AROON(self.high, self.low)
expecteddf = DataFrame({"AROOND_14": expected[0], "AROONU_14": expected[1]})
pdt.assert_frame_equal(result, expecteddf)
- except AssertionError as ae:
+ except AssertionError:
try:
aroond_corr = pandas_ta.utils.df_error_analysis(result.iloc[:, 0], expecteddf.iloc[:, 0], col=CORRELATION)
self.assertGreater(aroond_corr, CORRELATION_THRESHOLD)
@@ -76,13 +80,19 @@ def test_aroon(self):
except Exception as ex:
error_analysis(result.iloc[:, 1], CORRELATION, ex, newline=False)
+ result = pandas_ta.aroon(self.high, self.low)
+ self.assertIsInstance(result, DataFrame)
+ self.assertEqual(result.name, "AROON_14")
+
def test_aroon_osc(self):
result = pandas_ta.aroon(self.high, self.low)
+ self.assertIsInstance(result, DataFrame)
+ self.assertEqual(result.name, "AROON_14")
try:
expected = tal.AROONOSC(self.high, self.low)
pdt.assert_series_equal(result.iloc[:, 2], expected)
- except AssertionError as ae:
+ except AssertionError:
try:
aroond_corr = pandas_ta.utils.df_error_analysis(result.iloc[:,2], expected,col=CORRELATION)
self.assertGreater(aroond_corr, CORRELATION_THRESHOLD)
@@ -158,7 +168,7 @@ def test_psar(self):
try:
expected = tal.SAR(self.high, self.low)
pdt.assert_series_equal(psar, expected)
- except AssertionError as ae:
+ except AssertionError:
try:
psar_corr = pandas_ta.utils.df_error_analysis(psar, expected, col=CORRELATION)
self.assertGreater(psar_corr, CORRELATION_THRESHOLD)
diff --git a/tests/test_indicator_volatility.py b/tests/test_indicator_volatility.py
index 39b149ad..381a9d16 100644
--- a/tests/test_indicator_volatility.py
+++ b/tests/test_indicator_volatility.py
@@ -45,26 +45,26 @@ def test_accbands(self):
self.assertEqual(result.name, "ACCBANDS_20")
def test_atr(self):
- result = pandas_ta.atr(self.high, self.low, self.close)
+ result = pandas_ta.atr(self.high, self.low, self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "ATRr_14")
try:
expected = tal.ATR(self.high, self.low, self.close)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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_bbands(self):
- result = pandas_ta.bbands(self.close, ddof=0)
- self.assertIsInstance(result, DataFrame)
- self.assertEqual(result.name, "BBANDS_5_2.0")
+ result = pandas_ta.atr(self.high, self.low, self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "ATRr_14")
- result = pandas_ta.bbands(self.close, ddof=1)
+ def test_bbands(self):
+ result = pandas_ta.bbands(self.close, talib=False)
self.assertIsInstance(result, DataFrame)
self.assertEqual(result.name, "BBANDS_5_2.0")
@@ -72,7 +72,7 @@ def test_bbands(self):
expected = tal.BBANDS(self.close)
expecteddf = DataFrame({"BBU_5_2.0": expected[0], "BBM_5_2.0": expected[1], "BBL_5_2.0": expected[2]})
pdt.assert_frame_equal(result, expecteddf)
- except AssertionError as ae:
+ except AssertionError:
try:
bbl_corr = pandas_ta.utils.df_error_analysis(result.iloc[:, 0], expecteddf.iloc[:,0], col=CORRELATION)
self.assertGreater(bbl_corr, CORRELATION_THRESHOLD)
@@ -91,6 +91,14 @@ def test_bbands(self):
except Exception as ex:
error_analysis(result.iloc[:, 2], CORRELATION, ex, newline=False)
+ result = pandas_ta.bbands(self.close, ddof=0)
+ self.assertIsInstance(result, DataFrame)
+ self.assertEqual(result.name, "BBANDS_5_2.0")
+
+ result = pandas_ta.bbands(self.close, ddof=1)
+ self.assertIsInstance(result, DataFrame)
+ self.assertEqual(result.name, "BBANDS_5_2.0")
+
def test_donchian(self):
result = pandas_ta.donchian(self.high, self.low)
self.assertIsInstance(result, DataFrame)
@@ -115,20 +123,24 @@ def test_massi(self):
self.assertEqual(result.name, "MASSI_9_25")
def test_natr(self):
- result = pandas_ta.natr(self.high, self.low, self.close)
+ result = pandas_ta.natr(self.high, self.low, self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "NATR_14")
try:
expected = tal.NATR(self.high, self.low, self.close)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.natr(self.high, self.low, self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "NATR_14")
+
def test_pdist(self):
result = pandas_ta.pdist(self.open, self.high, self.low, self.close)
self.assertIsInstance(result, Series)
@@ -153,20 +165,24 @@ def test_thermo(self):
self.assertEqual(result.name, "THERMO_20_2_0.5")
def test_true_range(self):
- result = pandas_ta.true_range(self.high, self.low, self.close)
+ result = pandas_ta.true_range(self.high, self.low, self.close, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "TRUERANGE_1")
try:
expected = tal.TRANGE(self.high, self.low, self.close)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.true_range(self.high, self.low, self.close)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "TRUERANGE_1")
+
def test_ui(self):
result = pandas_ta.ui(self.close)
self.assertIsInstance(result, Series)
diff --git a/tests/test_indicator_volume.py b/tests/test_indicator_volume.py
index 6dda44a9..dae1f54d 100644
--- a/tests/test_indicator_volume.py
+++ b/tests/test_indicator_volume.py
@@ -35,40 +35,48 @@ def tearDown(self): pass
def test_ad(self):
- result = pandas_ta.ad(self.high, self.low, self.close, self.volume_)
+ result = pandas_ta.ad(self.high, self.low, self.close, self.volume_, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "AD")
try:
expected = tal.AD(self.high, self.low, self.close, self.volume_)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.ad(self.high, self.low, self.close, self.volume_)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "AD")
+
def test_ad_open(self):
result = pandas_ta.ad(self.high, self.low, self.close, self.volume_, self.open)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "ADo")
def test_adosc(self):
- result = pandas_ta.adosc(self.high, self.low, self.close, self.volume_)
+ result = pandas_ta.adosc(self.high, self.low, self.close, self.volume_, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "ADOSC_3_10")
try:
expected = tal.ADOSC(self.high, self.low, self.close, self.volume_)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.adosc(self.high, self.low, self.close, self.volume_)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "ADOSC_3_10")
+
def test_aobv(self):
result = pandas_ta.aobv(self.close, self.volume_)
self.assertIsInstance(result, DataFrame)
@@ -95,40 +103,48 @@ def test_kvo(self):
self.assertEqual(result.name, "KVO_34_55_13")
def test_mfi(self):
- result = pandas_ta.mfi(self.high, self.low, self.close, self.volume_)
+ result = pandas_ta.mfi(self.high, self.low, self.close, self.volume_, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "MFI_14")
try:
expected = tal.MFI(self.high, self.low, self.close, self.volume_)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.mfi(self.high, self.low, self.close, self.volume_)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "MFI_14")
+
def test_nvi(self):
result = pandas_ta.nvi(self.close, self.volume_)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "NVI_1")
def test_obv(self):
- result = pandas_ta.obv(self.close, self.volume_)
+ result = pandas_ta.obv(self.close, self.volume_, talib=False)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "OBV")
try:
expected = tal.OBV(self.close, self.volume_)
pdt.assert_series_equal(result, expected, check_names=False)
- except AssertionError as ae:
+ except AssertionError:
try:
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)
+ result = pandas_ta.obv(self.close, self.volume_)
+ self.assertIsInstance(result, Series)
+ self.assertEqual(result.name, "OBV")
+
def test_pvi(self):
result = pandas_ta.pvi(self.close, self.volume_)
self.assertIsInstance(result, Series)
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 06cc553a..b1f686f9 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -149,12 +149,15 @@ def test_df_dates(self):
result = self.utils.df_dates(self.data, ["1999-11-01", "2020-08-15", "2020-08-24", "2020-08-25", "2020-08-26", "2020-08-27"])
self.assertEqual(5, result.shape[0])
+ @skip
def test_df_month_to_date(self):
result = self.utils.df_month_to_date(self.data)
+ @skip
def test_df_quarter_to_date(self):
result = self.utils.df_quarter_to_date(self.data)
+ @skip
def test_df_year_to_date(self):
result = self.utils.df_year_to_date(self.data)
@@ -274,6 +277,18 @@ def test_symmetric_triangle(self):
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)
+ def test_tal_ma(self):
+ self.assertEqual(self.utils.tal_ma("sma"), 0)
+ self.assertEqual(self.utils.tal_ma("Sma"), 0)
+ self.assertEqual(self.utils.tal_ma("ema"), 1)
+ self.assertEqual(self.utils.tal_ma("wma"), 2)
+ self.assertEqual(self.utils.tal_ma("dema"), 3)
+ self.assertEqual(self.utils.tal_ma("tema"), 4)
+ self.assertEqual(self.utils.tal_ma("trima"), 5)
+ self.assertEqual(self.utils.tal_ma("kama"), 6)
+ self.assertEqual(self.utils.tal_ma("mama"), 7)
+ self.assertEqual(self.utils.tal_ma("t3"), 8)
+
def test_zero(self):
self.assertEqual(self.utils.zero(-0.0000000000000001), 0)
self.assertEqual(self.utils.zero(0), 0)
diff --git a/tests/test_utils_metrics.py b/tests/test_utils_metrics.py
index 0f1a418e..6d45a923 100644
--- a/tests/test_utils_metrics.py
+++ b/tests/test_utils_metrics.py
@@ -1,10 +1,9 @@
-from .config import sample_data
-from .context import pandas_ta
-
from unittest import skip, TestCase
from pandas import DataFrame
+from .config import sample_data
+from .context import pandas_ta
class TestUtilityMetrics(TestCase):
@@ -97,7 +96,6 @@ def test_optimal_leverage(self):
def test_pure_profit_score(self):
result = pandas_ta.pure_profit_score(self.close)
- self.assertIsInstance(result, float)
self.assertGreaterEqual(result, 0)
def test_sharpe_ratio(self):