diff --git a/.gitignore b/.gitignore index d6915cb..21e8f1f 100644 --- a/.gitignore +++ b/.gitignore @@ -151,6 +151,7 @@ pandas_pips reqs.txt requirements.txt qd.py +tds.py simple.ipynb ta.json diff --git a/README.md b/README.md index c891fbc..377ca43 100644 --- a/README.md +++ b/README.md @@ -611,6 +611,7 @@ Use parameter: cumulative=**True** for cumulative results. ## **Breaking** +* _Bollinger Bands_ (**bbands**): New column 'bandwidth' appended to the returning DataFrame. See: ```help(ta.bbands)``` * _Stochastic Oscillator_ (**stoch**): Now in line with Trading View's calculation. See: ```help(ta.stoch)``` * _Linear Decay_ (**linear_decay**): Renamed to _Decay_ (**decay**) and with the option for Exponential decay using ```mode="exp"```. See: ```help(ta.decay)``` diff --git a/pandas_ta/momentum/bias.py b/pandas_ta/momentum/bias.py index 9aa4b41..5f61cd7 100644 --- a/pandas_ta/momentum/bias.py +++ b/pandas_ta/momentum/bias.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- from pandas_ta.overlap import ema, hma, rma, sma, wma -from pandas_ta.utils import get_offset, verify_series, zero +from pandas_ta.utils import get_offset, verify_series def bias(close, length=None, mamode=None, offset=None, **kwargs): diff --git a/pandas_ta/volatility/bbands.py b/pandas_ta/volatility/bbands.py index b835a90..ec4b5a7 100644 --- a/pandas_ta/volatility/bbands.py +++ b/pandas_ta/volatility/bbands.py @@ -26,30 +26,40 @@ def bbands(close, length=None, std=None, mamode=None, offset=None, **kwargs): lower = mid - deviations upper = mid + deviations + bandwidth = 100 * (upper - lower) / mid + # Offset if offset != 0: lower = lower.shift(offset) mid = mid.shift(offset) upper = upper.shift(offset) + bandwidth = bandwidth.shift(offset) # Handle fills if "fillna" in kwargs: lower.fillna(kwargs["fillna"], inplace=True) mid.fillna(kwargs["fillna"], inplace=True) upper.fillna(kwargs["fillna"], inplace=True) + bandwidth.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: lower.fillna(method=kwargs["fill_method"], inplace=True) mid.fillna(method=kwargs["fill_method"], inplace=True) upper.fillna(method=kwargs["fill_method"], inplace=True) + bandwidth.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it lower.name = f"BBL_{length}_{std}" mid.name = f"BBM_{length}_{std}" upper.name = f"BBU_{length}_{std}" - mid.category = upper.category = lower.category = "volatility" + bandwidth.name = f"BBB_{length}_{std}" + upper.category = lower.category = "volatility" + mid.category = bandwidth.category = upper.category # Prepare DataFrame to return - data = {lower.name: lower, mid.name: mid, upper.name: upper} + data = { + lower.name: lower, mid.name: mid, + upper.name: upper, bandwidth.name: bandwidth + } bbandsdf = DataFrame(data) bbandsdf.name = f"BBANDS_{length}_{std}" bbandsdf.category = mid.category @@ -80,17 +90,19 @@ Calculation: LOWER = MID - std * stdev UPPER = MID + std * stdev + BANDWIDTH = 100 * (UPPER - LOWER) / MID + Args: close (pd.Series): Series of 'close's - length (int): The short period. Default: 20 - std (int): The long period. Default: 2 - mamode (str): Two options: "sma" or "ema". Default: "ema" - offset (int): How many periods to offset the result. Default: 0 + length (int): The short period. Default: 20 + std (int): The long period. Default: 2 + mamode (str): Two options: "sma" or "ema". Default: "ema" + offset (int): How many periods to offset the result. Default: 0 Kwargs: fillna (value, optional): pd.DataFrame.fillna(value) fill_method (value, optional): Type of fill method Returns: - pd.DataFrame: lower, mid, upper columns. + pd.DataFrame: lower, mid, upper, bandwidth columns. """ diff --git a/setup.py b/setup.py index 2901948..bafe02c 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ setup( "pandas_ta.volatility", "pandas_ta.volume" ], - version=".".join(("0", "2", "27b")), + version=".".join(("0", "2", "28b")), description=long_description, long_description=long_description, author="Kevin Johnson", diff --git a/tests/test_ext_indicator_volatility.py b/tests/test_ext_indicator_volatility.py index 3b7943d..959ff2c 100644 --- a/tests/test_ext_indicator_volatility.py +++ b/tests/test_ext_indicator_volatility.py @@ -36,7 +36,7 @@ class TestVolatilityExtension(TestCase): def test_bbands_ext(self): self.data.ta.bbands(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(list(self.data.columns[-3:]), ["BBL_5_2.0", "BBM_5_2.0", "BBU_5_2.0"]) + self.assertEqual(list(self.data.columns[-4:]), ["BBL_5_2.0", "BBM_5_2.0", "BBU_5_2.0", "BBB_5_2.0"]) def test_donchian_ext(self): self.data.ta.donchian(append=True) diff --git a/tests/test_strategy.py b/tests/test_strategy.py index f940988..ebd7e79 100644 --- a/tests/test_strategy.py +++ b/tests/test_strategy.py @@ -126,7 +126,7 @@ class TestStrategyMethods(TestCase): def test_custom_col_names_tuple(self): self.category = "Custom C" - custom_args_ta = [{"kind": "bbands", "col_names": ("LB", "MB", "UB")}] + custom_args_ta = [{"kind": "bbands", "col_names": ("LB", "MB", "UB", "BW")}] custom = pandas_ta.Strategy( "Custom Col Numbers Tuple",