diff --git a/pandas_ta/overlap/rma.py b/pandas_ta/overlap/rma.py index 11ec03e..72584de 100644 --- a/pandas_ta/overlap/rma.py +++ b/pandas_ta/overlap/rma.py @@ -39,8 +39,7 @@ def rma( alpha = (1.0 / length) if length > 0 else 0.5 offset = v_offset(offset) - # Calculate - rma = close.ewm(alpha=alpha, min_periods=length).mean() + rma = close.ewm(alpha=alpha, adjust=False).mean() # Offset if offset != 0: diff --git a/pandas_ta/volatility/atr.py b/pandas_ta/volatility/atr.py index ca7e7a2..3f0c011 100644 --- a/pandas_ta/volatility/atr.py +++ b/pandas_ta/volatility/atr.py @@ -1,16 +1,25 @@ # -*- coding: utf-8 -*- +from numpy import nan from pandas import Series from pandas_ta._typing import DictLike, Int from pandas_ta.ma import ma from pandas_ta.maps import Imports -from pandas_ta.utils import v_drift, v_mamode, v_offset -from pandas_ta.utils import v_pos_default, v_series, v_talib +from pandas_ta.utils import ( + v_bool, + v_drift, + v_mamode, + v_offset, + v_pos_default, + v_series, + v_talib +) from .true_range import true_range def atr( high: Series, low: Series, close: Series, length: Int = None, - mamode: str = None, talib: bool = None, drift: Int = None, + mamode: str = None, talib: bool = None, + prenan: bool = None, drift: Int = None, offset: Int = None, **kwargs: DictLike ) -> Series: """Average True Range (ATR) @@ -29,6 +38,8 @@ def atr( 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 + prenan (bool): If True, behave like TA Lib with some initial nan + based on drift (typically 1). Default: False drift (int): The difference period. Default: 1 offset (int): How many periods to offset the result. Default: 0 @@ -51,6 +62,7 @@ def atr( mamode = v_mamode(mamode, "rma") mode_tal = v_talib(talib) + prenan = v_bool(prenan, False) drift = v_drift(drift) offset = v_offset(offset) @@ -60,8 +72,12 @@ def atr( atr = ATR(high, low, close, length) else: tr = true_range( - high=high, low=low, close=close, drift=drift, talib=mode_tal + high=high, low=low, close=close, + talib=mode_tal, prenan=prenan, drift=drift ) + sma_nth = tr[0:length].mean() + tr[:length - 1] = nan + tr.iloc[length - 1] = sma_nth atr = ma(mamode, tr, length=length, talib=mode_tal) percent = kwargs.pop("percent", False) diff --git a/pandas_ta/volatility/true_range.py b/pandas_ta/volatility/true_range.py index 372662c..2d69870 100644 --- a/pandas_ta/volatility/true_range.py +++ b/pandas_ta/volatility/true_range.py @@ -3,13 +3,13 @@ from numpy import nan from pandas import concat, Series from pandas_ta._typing import DictLike, Int from pandas_ta.maps import Imports -from pandas_ta.utils import non_zero_range, v_drift, v_offset -from pandas_ta.utils import v_series, v_talib +from pandas_ta.utils import non_zero_range, v_bool, v_drift +from pandas_ta.utils import v_offset, v_series, v_talib def true_range( high: Series, low: Series, close: Series, - talib: bool = None, drift: Int = None, + talib: bool = None, prenan: bool = None, drift: Int = None, offset: Int = None, **kwargs: DictLike ) -> Series: """True Range @@ -26,6 +26,8 @@ def true_range( 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 + prenan (bool): If True, behave like TA Lib with some initial nan + based on drift (typically 1). Default: False drift (int): The shift period. Default: 1 offset (int): How many periods to offset the result. Default: 0 @@ -41,6 +43,7 @@ def true_range( low = v_series(low) close = v_series(close) mode_tal = v_talib(talib) + prenan = v_bool(prenan, False) drift = v_drift(drift) offset = v_offset(offset) @@ -54,7 +57,8 @@ def true_range( ranges = [hl_range, high - pc, pc - low] true_range = concat(ranges, axis=1) true_range = true_range.abs().max(axis=1) - true_range.iloc[:drift] = nan + if prenan: + true_range.iloc[:drift] = nan # Offset if offset != 0: diff --git a/setup.py b/setup.py index 464d1a9..347005c 100644 --- a/setup.py +++ b/setup.py @@ -42,6 +42,7 @@ setup( "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", "Operating System :: OS Independent", "License :: OSI Approved :: MIT License", "Natural Language :: English", @@ -64,8 +65,8 @@ setup( extras_require={ "full": [ "alphaVantage-api", "matplotlib", "mplfinance", "numba", "polygon" - "scipy", "sklearn", "statsmodels", "stochastic", "ta-lib", "tqdm", - "vectorbt", "yfinance", + "python-dotenv", "scipy", "sklearn", "statsmodels", "stochastic", + "ta-lib", "tqdm", "vectorbt", "yfinance", ], "test": ["ta-lib"], }, diff --git a/tests/config.py b/tests/config.py index d08abdc..215acce 100644 --- a/tests/config.py +++ b/tests/config.py @@ -2,6 +2,7 @@ import datetime from pathlib import Path +from numpy import array from pandas import DataFrame, read_csv import pandas_datareader as pdr @@ -17,6 +18,13 @@ CORRELATION: str = "corr" # "sem" CORRELATION_THRESHOLD: IntFloat = 0.99 # Less than 0.99 is undesirable VERBOSE: bool = False +welles_wilder_df = DataFrame({ + "open": array([50, 50.7, 51.7, 52.5, 53.6, 54.4, 52.9, 52]), + "high": array([51.2, 51.8, 52.9, 53.7, 54.8, 54.4, 53.2, 52.7]), + "low": array([49.8, 50.3, 51.7, 52.3, 53.5, 52.9, 52, 52]), + "close": array([50.9, 51.5, 52.8, 53.5, 54.7, 53, 52, 52.2]) +}) + def error_analysis( df: DataFrame, kind: str, msg: str, diff --git a/tests/test_indicator_overlap.py b/tests/test_indicator_overlap.py index 9c0968f..f674a76 100644 --- a/tests/test_indicator_overlap.py +++ b/tests/test_indicator_overlap.py @@ -6,7 +6,12 @@ from pandas import DataFrame, Series import talib as tal -from .config import CORRELATION, CORRELATION_THRESHOLD, error_analysis, sample_data +from .config import ( + CORRELATION, + CORRELATION_THRESHOLD, + error_analysis, + sample_data, +) from .context import pandas_ta