diff --git a/.gitignore b/.gitignore index 4a89bd2..99f8115 100644 --- a/.gitignore +++ b/.gitignore @@ -135,5 +135,6 @@ reqs.txt requirements.txt qd.py _performance.py +_volatility.py _volume.py simple.ipynb \ No newline at end of file diff --git a/pandas_ta/__init__.py b/pandas_ta/__init__.py index 56cf596..a173168 100644 --- a/pandas_ta/__init__.py +++ b/pandas_ta/__init__.py @@ -23,6 +23,16 @@ from .performance.log_return import log_return from .performance.percent_return import percent_return from .performance.trend_return import trend_return +# Volatility +from .volatility.accbands import accbands +from .volatility.atr import atr +from .volatility.bbands import bbands +from .volatility.donchian import donchian +from .volatility.kc import kc +from .volatility.massi import massi +from .volatility.natr import natr +from .volatility.true_range import true_range + # Volume from .volume.ad import ad from .volume.adosc import adosc @@ -39,4 +49,5 @@ from .volume.pvt import pvt from .volume.vp import vp # DataFrame Extension -from .core import * \ No newline at end of file +from .core import * + diff --git a/pandas_ta/core.py b/pandas_ta/core.py index 3da2ef4..0900d49 100644 --- a/pandas_ta/core.py +++ b/pandas_ta/core.py @@ -8,7 +8,6 @@ from .overlap import * from .statistics import * from .trend import * from .utils import * -from .volatility import * class BasePandasObject(PandasObject): """Simple PandasObject Extension @@ -664,6 +663,7 @@ class AnalysisIndicators(BasePandasObject): high = self._get_column(high, 'high') low = self._get_column(low, 'low') close = self._get_column(close, 'close') + from pandas_ta.volatility.accbands import accbands result = accbands(high=high, low=low, close=close, length=length, c=c, mamode=mamode, offset=offset, **kwargs) self._append(result, **kwargs) return result @@ -672,18 +672,21 @@ class AnalysisIndicators(BasePandasObject): high = self._get_column(high, 'high') low = self._get_column(low, 'low') close = self._get_column(close, 'close') + from pandas_ta.volatility.atr import atr result = atr(high=high, low=low, close=close, length=length, mamode=mamode, offset=offset, **kwargs) self._append(result, **kwargs) return result def bbands(self, close=None, length=None, stdev=None, mamode=None, offset=None, **kwargs): close = self._get_column(close, 'close') + from pandas_ta.volatility.bbands import bbands result = bbands(close=close, length=length, stdev=stdev, mamode=mamode, offset=offset, **kwargs) self._append(result, **kwargs) return result def donchian(self, close=None, length=None, offset=None, **kwargs): close = self._get_column(close, 'close') + from pandas_ta.volatility.donchian import donchian result = donchian(close=close, length=length, offset=offset, **kwargs) self._append(result, **kwargs) return result @@ -692,6 +695,7 @@ class AnalysisIndicators(BasePandasObject): high = self._get_column(high, 'high') low = self._get_column(low, 'low') close = self._get_column(close, 'close') + from pandas_ta.volatility.kc import kc result = kc(high=high, low=low, close=close, length=length, scalar=scalar, mamode=mamode, offset=offset, **kwargs) self._append(result, **kwargs) return result @@ -699,6 +703,7 @@ class AnalysisIndicators(BasePandasObject): def massi(self, high=None, low=None, fast=None, slow=None, offset=None, **kwargs): high = self._get_column(high, 'high') low = self._get_column(low, 'low') + from pandas_ta.volatility.massi import massi result = massi(high=high, low=low, fast=fast, slow=slow, offset=offset, **kwargs) self._append(result, **kwargs) return result @@ -707,6 +712,7 @@ class AnalysisIndicators(BasePandasObject): high = self._get_column(high, 'high') low = self._get_column(low, 'low') close = self._get_column(close, 'close') + from pandas_ta.volatility.natr import natr result = natr(high=high, low=low, close=close, length=length, mamode=mamode, offset=offset, **kwargs) self._append(result, **kwargs) return result @@ -715,6 +721,7 @@ class AnalysisIndicators(BasePandasObject): high = self._get_column(high, 'high') low = self._get_column(low, 'low') close = self._get_column(close, 'close') + from pandas_ta.volatility.true_range import true_range result = true_range(high=high, low=low, close=close, drift=drift, offset=offset, **kwargs) self._append(result, **kwargs) return result diff --git a/pandas_ta/trend.py b/pandas_ta/trend.py index e7c3367..1d9f494 100644 --- a/pandas_ta/trend.py +++ b/pandas_ta/trend.py @@ -5,7 +5,8 @@ import pandas as pd from .momentum import roc from .overlap import dema, ema, hma, midprice, rma, sma from .utils import get_drift, get_offset, verify_series, zero -from .volatility import atr, true_range +from .volatility.true_range import true_range +from .volatility.atr import atr diff --git a/pandas_ta/volatility.py b/pandas_ta/volatility.py deleted file mode 100644 index 19f3346..0000000 --- a/pandas_ta/volatility.py +++ /dev/null @@ -1,662 +0,0 @@ -# -*- coding: utf-8 -*- -import numpy as np -import pandas as pd - -from .overlap import ema, hlc3, sma -from .statistics import variance, stdev -from .utils import * - - - -def accbands(high, low, close, length=None, c=None, drift=None, mamode=None, offset=None, **kwargs): - """Indicator: Acceleration Bands (ACCBANDS) - https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/acceleration-bands-abands/ - """ - # Validate arguments - high = verify_series(high) - low = verify_series(low) - close = verify_series(close) - length = int(length) if length and length > 0 else 20 - c = float(c) if c and c > 0 else 4 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length - mamode = mamode.lower() if mamode else 'sma' - drift = get_drift(drift) - offset = get_offset(offset) - - # Calculate Result - hl_ratio = (high - low) / (high + low) - hl_ratio *= c - _lower = low * (1 - hl_ratio) - _upper = high * (1 + hl_ratio) - - if mamode is None or mamode == 'sma': - lower = _lower.rolling(length, min_periods=min_periods).mean() - mid = close.rolling(length, min_periods=min_periods).mean() - upper = _upper.rolling(length, min_periods=min_periods).mean() - elif mamode == 'ema': - lower = _lower.ewm(span=length, min_periods=min_periods).mean() - mid = close.ewm(span=length, min_periods=min_periods).mean() - upper = _upper.ewm(span=length, min_periods=min_periods).mean() - - # Offset - if offset != 0: - lower = lower.shift(offset) - mid = mid.shift(offset) - upper = upper.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) - 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) - - # Name and Categorize it - lower.name = f"ACCBL_{length}" - mid.name = f"ACCBM_{length}" - upper.name = f"ACCBU_{length}" - mid.category = upper.category = lower.category = 'volatility' - - # Prepare DataFrame to return - data = {lower.name: lower, mid.name: mid, upper.name: upper} - accbandsdf = pd.DataFrame(data) - accbandsdf.name = f"ACCBANDS_{length}" - accbandsdf.category = 'volatility' - - return accbandsdf - - -def atr(high, low, close, length=None, mamode=None, drift=None, offset=None, **kwargs): - """Indicator: Average True Range (ATR)""" - # Validate arguments - high = verify_series(high) - low = verify_series(low) - close = verify_series(close) - length = int(length) if length and length > 0 else 14 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length - mamode = mamode.lower() if mamode else 'ema' - drift = get_drift(drift) - offset = get_offset(offset) - - # Calculate Result - tr = true_range(high=high, low=low, close=close, drift=drift) - if mamode == 'ema': - atr = tr.ewm(span=length, min_periods=min_periods).mean() - else: - atr = tr.rolling(length, min_periods=min_periods).mean() - - # Offset - if offset != 0: - atr = atr.shift(offset) - - # Handle fills - if 'fillna' in kwargs: - atr.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - atr.fillna(method=kwargs['fill_method'], inplace=True) - - # Name and Categorize it - atr.name = f"ATR_{length}" - atr.category = 'volatility' - - return atr - - -def bbands(close, length=None, std=None, mamode=None, offset=None, **kwargs): - """Indicator: Bollinger Bands (BBANDS)""" - # Validate arguments - close = verify_series(close) - length = int(length) if length and length > 0 else 20 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length - std = float(std) if std and std > 0 else 2. - mamode = mamode.lower() if mamode else 'sma' - offset = get_offset(offset) - - # Calculate Result - standard_deviation = stdev(close=close, length=length) - deviations = std * standard_deviation - - if mamode is None or mamode == 'sma': - mid = sma(close=close, length=length) - elif mamode == 'ema': - mid = ema(close=close, length=length, **kwargs) - - lower = mid - deviations - upper = mid + deviations - - # Offset - if offset != 0: - lower = lower.shift(offset) - mid = mid.shift(offset) - upper = upper.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) - 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) - - # Name and Categorize it - lower.name = f"BBL_{length}" - mid.name = f"BBM_{length}" - upper.name = f"BBU_{length}" - mid.category = upper.category = lower.category = 'volatility' - - # Prepare DataFrame to return - data = {lower.name: lower, mid.name: mid, upper.name: upper} - bbandsdf = pd.DataFrame(data) - bbandsdf.name = f"BBANDS_{length}" - bbandsdf.category = 'volatility' - - return bbandsdf - - -def donchian(close, lower_length=None, upper_length=None, offset=None, **kwargs): - """Indicator: Donchian Channels (DC)""" - # Validate arguments - close = verify_series(close) - lower_length = int(lower_length) if lower_length and lower_length > 0 else 10 - upper_length = int(upper_length) if upper_length and upper_length > 0 else 20 - lower_min_periods = int(kwargs['lower_min_periods']) if 'lower_min_periods' in kwargs and kwargs['lower_min_periods'] is not None else lower_length - upper_min_periods = int(kwargs['upper_min_periods']) if 'upper_min_periods' in kwargs and kwargs['upper_min_periods'] is not None else upper_length - offset = get_offset(offset) - - # Calculate Result - lower = close.rolling(lower_length, min_periods=lower_min_periods).min() - upper = close.rolling(upper_length, min_periods=upper_min_periods).max() - mid = 0.5 * (lower + upper) - - # Handle fills - if 'fillna' in kwargs: - lower.fillna(kwargs['fillna'], inplace=True) - mid.fillna(kwargs['fillna'], inplace=True) - upper.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) - - # Offset - if offset != 0: - lower = lower.shift(offset) - mid = mid.shift(offset) - upper = upper.shift(offset) - - # Name and Categorize it - lower.name = f"DCL_{lower_length}_{upper_length}" - mid.name = f"DCM_{lower_length}_{upper_length}" - upper.name = f"DCU_{lower_length}_{upper_length}" - mid.category = upper.category = lower.category = 'volatility' - - # Prepare DataFrame to return - data = {lower.name: lower, mid.name: mid, upper.name: upper} - dcdf = pd.DataFrame(data) - dcdf.name = f"DC_{lower_length}_{upper_length}" - dcdf.category = 'volatility' - - return dcdf - - -def kc(high, low, close, length=None, scalar=None, mamode=None, offset=None, **kwargs): - """Indicator: Keltner Channels (KC)""" - # Validate arguments - high = verify_series(high) - low = verify_series(low) - close = verify_series(close) - length = int(length) if length and length > 0 else 20 - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length - scalar = float(scalar) if scalar and scalar > 0 else 2 - mamode = mamode.lower() if mamode else None - offset = get_offset(offset) - - # Calculate Result - std = variance(close=close, length=length).apply(np.sqrt) - - if mamode == 'ema': - basis = close.ewm(span=length, min_periods=min_periods).mean() - band = atr(high=high, low=low, close=close) - else: - hl_range = high - low - typical_price = hlc3(high=high, low=low, close=close) - basis = typical_price.rolling(length, min_periods=min_periods).mean() - band = hl_range.rolling(length, min_periods=min_periods).mean() - - lower = basis - scalar * band - upper = basis + scalar * band - - # Offset - if offset != 0: - lower = lower.shift(offset) - basis = basis.shift(offset) - upper = upper.shift(offset) - - # Handle fills - if 'fillna' in kwargs: - lower.fillna(kwargs['fillna'], inplace=True) - basis.fillna(kwargs['fillna'], inplace=True) - upper.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - lower.fillna(method=kwargs['fill_method'], inplace=True) - basis.fillna(method=kwargs['fill_method'], inplace=True) - upper.fillna(method=kwargs['fill_method'], inplace=True) - - # Name and Categorize it - lower.name = f"KCL_{length}" - basis.name = f"KCB_{length}" - upper.name = f"KCU_{length}" - basis.category = upper.category = lower.category = 'volatility' - - # Prepare DataFrame to return - data = {lower.name: lower, basis.name: basis, upper.name: upper} - kcdf = pd.DataFrame(data) - kcdf.name = f"KC_{length}" - kcdf.category = 'volatility' - - return kcdf - - -def massi(high, low, fast=None, slow=None, offset=None, **kwargs): - """Indicator: Mass Index (MASSI)""" - # Validate arguments - high = verify_series(high) - low = verify_series(low) - fast = int(fast) if fast and fast > 0 else 9 - slow = int(slow) if slow and slow > 0 else 25 - if slow < fast: - fast, slow = slow, fast - min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else fast - offset = get_offset(offset) - - # Calculate Result - hl_range = high - low - hl_ema1 = ema(close=hl_range, length=fast, **kwargs) - hl_ema2 = ema(close=hl_ema1, length=fast, **kwargs) - - hl_ratio = hl_ema1 / hl_ema2 - massi = hl_ratio.rolling(slow, min_periods=slow).sum() - - # Offset - if offset != 0: - massi = massi.shift(offset) - - # Handle fills - if 'fillna' in kwargs: - massi.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - massi.fillna(method=kwargs['fill_method'], inplace=True) - - # Name and Categorize it - massi.name = f"MASSI_{fast}_{slow}" - massi.category = 'volatility' - - return massi - - -def natr(high, low, close, length=None, mamode=None, drift=None, offset=None, **kwargs): - """Indicator: Normalized Average True Range (NATR)""" - # Validate arguments - high = verify_series(high) - low = verify_series(low) - close = verify_series(close) - length = int(length) if length and length > 0 else 14 - mamode = mamode.lower() if mamode else 'ema' - drift = get_drift(drift) - offset = get_offset(offset) - - # Calculate Result - natr = (100 / close) * atr(high=high, low=low, close=close, length=length, mamode=mamode, drift=drift, offset=offset, **kwargs) - - # Offset - if offset != 0: - natr = natr.shift(offset) - - # Handle fills - if 'fillna' in kwargs: - natr.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - natr.fillna(method=kwargs['fill_method'], inplace=True) - - # Name and Categorize it - natr.name = f"NATR_{length}" - natr.category = 'volatility' - - return natr - - -def true_range(high, low, close, drift=None, offset=None, **kwargs): - """Indicator: True Range""" - # Validate arguments - high = verify_series(high) - low = verify_series(low) - close = verify_series(close) - drift = get_drift(drift) - offset = get_offset(offset) - - # Calculate Result - prev_close = close.shift(drift) - ranges = [high - low, high - prev_close, low - prev_close] - true_range = pd.DataFrame(ranges).T - true_range = true_range.abs().max(axis=1) - - # Offset - if offset != 0: - true_range = true_range.shift(offset) - - # Handle fills - if 'fillna' in kwargs: - true_range.fillna(kwargs['fillna'], inplace=True) - if 'fill_method' in kwargs: - true_range.fillna(method=kwargs['fill_method'], inplace=True) - - # Name and Categorize it - true_range.name = f"TRUERANGE_{drift}" - true_range.category = 'volatility' - - return true_range - - - -# Volatility Documentation -accbands.__doc__ = \ -"""Acceleration Bands (ACCBANDS) - -Acceleration Bands created by Price Headley plots upper and lower envelope -bands around a simple moving average. - -Sources: - https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/acceleration-bands-abands/ - -Calculation: - Default Inputs: - length=10, c=4 - EMA = Exponential Moving Average - SMA = Simple Moving Average - HL_RATIO = c * (high - low) / (high + low) - LOW = low * (1 - HL_RATIO) - HIGH = high * (1 + HL_RATIO) - - if 'ema': - LOWER = EMA(LOW, length) - MID = EMA(close, length) - UPPER = EMA(HIGH, length) - else: - LOWER = SMA(LOW, length) - MID = SMA(close, length) - UPPER = SMA(HIGH, length) - -Args: - high (pd.Series): Series of 'high's - low (pd.Series): Series of 'low's - 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' - drift (int): The difference period. Default: 1 - 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. -""" - - -atr.__doc__ = \ -"""Average True Range (ATR) - -Averge True Range is used to measure volatility, especially -volatility caused by gaps or limit moves. - -Sources: - https://www.tradingview.com/wiki/Average_True_Range_(ATR) - -Calculation: - Default Inputs: - length=14, drift=1 - SMA = Simple Moving Average - EMA = Exponential Moving Average - TR = True Range - tr = TR(high, low, close, drift) - if 'ema': - ATR = EMA(tr, length) - else: - ATR = SMA(tr, length) - -Args: - high (pd.Series): Series of 'high's - low (pd.Series): Series of 'low's - close (pd.Series): Series of 'close's - length (int): It's period. Default: 14 - mamode (str): Two options: None or 'ema'. Default: 'ema' - drift (int): The difference period. Default: 1 - 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. -""" - - -bbands.__doc__ = \ -"""Bollinger Bands (BBANDS) - -A popular volatility indicator. - -Sources: - https://www.tradingview.com/wiki/Bollinger_Bands_(BB) - -Calculation: - Default Inputs: - length=20, std=2 - EMA = Exponential Moving Average - SMA = Simple Moving Average - STDEV = Standard Deviation - stdev = STDEV(close, length) - if 'ema': - MID = EMA(close, length) - else: - MID = SMA(close, length) - - LOWER = MID - std * stdev - UPPER = MID + std * stdev - -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: None 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. -""" - - -donchian.__doc__ = \ -"""Donchian Channels (DC) - -Donchian Channels are used to measure volatility, similar to -Bollinger Bands and Keltner Channels. - -Sources: - https://www.tradingview.com/wiki/Donchian_Channels_(DC) - -Calculation: - Default Inputs: - length=20 - LOWER = close.rolling(length).min() - UPPER = close.rolling(length).max() - MID = 0.5 * (LOWER + UPPER) - -Args: - close (pd.Series): Series of 'close's - length (int): The short period. Default: 20 - 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. -""" - - -kc.__doc__ = \ -"""Keltner Channels (KC) - -A popular volatility indicator similar to Bollinger Bands and -Donchian Channels. - -Sources: - https://www.tradingview.com/wiki/Keltner_Channels_(KC) - -Calculation: - Default Inputs: - length=20, scalar=2 - ATR = Average True Range - EMA = Exponential Moving Average - SMA = Simple Moving Average - if 'ema': - BASIS = EMA(close, length) - BAND = ATR(high, low, close) - else: - hl_range = high - low - tp = typical_price = hlc3(high, low, close) - BASIS = SMA(tp, length) - BAND = SMA(hl_range, length) - - LOWER = BASIS - scalar * BAND - UPPER = BASIS + scalar * BAND - -Args: - high (pd.Series): Series of 'high's - low (pd.Series): Series of 'low's - 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: None 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, basis, upper columns. -""" - - -massi.__doc__ = \ -"""Mass Index (MASSI) - -The Mass Index is a non-directional volatility indicator that utilitizes the -High-Low Range to identify trend reversals based on range expansions. - -Sources: - https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:mass_index - mi = sum(ema(high - low, 9) / ema(ema(high - low, 9), 9), length) - -Calculation: - Default Inputs: - fast: 9, slow: 25 - EMA = Exponential Moving Average - hl = high - low - hl_ema1 = EMA(hl, fast) - hl_ema2 = EMA(hl_ema1, fast) - hl_ratio = hl_ema1 / hl_ema2 - MASSI = SUM(hl_ratio, slow) - -Args: - high (pd.Series): Series of 'high's - low (pd.Series): Series of 'low's - fast (int): The short period. Default: 9 - slow (int): The long period. Default: 25 - 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. -""" - - -natr.__doc__ = \ -"""Normalized Average True Range (NATR) - -Normalized Average True Range attempt to normalize the average -true range. - -Sources: - https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/normalized-average-true-range-natr/ - -Calculation: - Default Inputs: - length=20 - ATR = Average True Range - NATR = (100 / close) * ATR(high, low, close) - -Args: - high (pd.Series): Series of 'high's - low (pd.Series): Series of 'low's - close (pd.Series): Series of 'close's - length (int): The short period. Default: 20 - 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 -""" - - -true_range.__doc__ = \ -"""True Range - -An method to expand a classical range (high minus low) to include -possible gap scenarios. - -Sources: - https://www.macroption.com/true-range/ - -Calculation: - Default Inputs: - drift=1 - ABS = Absolute Value - prev_close = close.shift(drift) - TRUE_RANGE = ABS([high - low, high - prev_close, low - prev_close]) - -Args: - high (pd.Series): Series of 'high's - low (pd.Series): Series of 'low's - close (pd.Series): Series of 'close's - drift (int): The shift period. Default: 1 - 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 -""" \ No newline at end of file diff --git a/pandas_ta/volatility/__init__.py b/pandas_ta/volatility/__init__.py new file mode 100644 index 0000000..7c68785 --- /dev/null +++ b/pandas_ta/volatility/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- \ No newline at end of file diff --git a/pandas_ta/volatility/accbands.py b/pandas_ta/volatility/accbands.py new file mode 100644 index 0000000..36317dc --- /dev/null +++ b/pandas_ta/volatility/accbands.py @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- +from pandas import DataFrame +from ..utils import get_drift, get_offset, verify_series + +def accbands(high, low, close, length=None, c=None, drift=None, mamode=None, offset=None, **kwargs): + """Indicator: Acceleration Bands (ACCBANDS)""" + # Validate arguments + high = verify_series(high) + low = verify_series(low) + close = verify_series(close) + length = int(length) if length and length > 0 else 20 + c = float(c) if c and c > 0 else 4 + min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + mamode = mamode.lower() if mamode else 'sma' + drift = get_drift(drift) + offset = get_offset(offset) + + # Calculate Result + hl_ratio = (high - low) / (high + low) + hl_ratio *= c + _lower = low * (1 - hl_ratio) + _upper = high * (1 + hl_ratio) + + if mamode is None or mamode == 'sma': + lower = _lower.rolling(length, min_periods=min_periods).mean() + mid = close.rolling(length, min_periods=min_periods).mean() + upper = _upper.rolling(length, min_periods=min_periods).mean() + elif mamode == 'ema': + lower = _lower.ewm(span=length, min_periods=min_periods).mean() + mid = close.ewm(span=length, min_periods=min_periods).mean() + upper = _upper.ewm(span=length, min_periods=min_periods).mean() + + # Offset + if offset != 0: + lower = lower.shift(offset) + mid = mid.shift(offset) + upper = upper.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) + 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) + + # Name and Categorize it + lower.name = f"ACCBL_{length}" + mid.name = f"ACCBM_{length}" + upper.name = f"ACCBU_{length}" + mid.category = upper.category = lower.category = 'volatility' + + # Prepare DataFrame to return + data = {lower.name: lower, mid.name: mid, upper.name: upper} + accbandsdf = DataFrame(data) + accbandsdf.name = f"ACCBANDS_{length}" + accbandsdf.category = 'volatility' + + return accbandsdf + + + +accbands.__doc__ = \ +"""Acceleration Bands (ACCBANDS) + +Acceleration Bands created by Price Headley plots upper and lower envelope +bands around a simple moving average. + +Sources: + https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/acceleration-bands-abands/ + +Calculation: + Default Inputs: + length=10, c=4 + EMA = Exponential Moving Average + SMA = Simple Moving Average + HL_RATIO = c * (high - low) / (high + low) + LOW = low * (1 - HL_RATIO) + HIGH = high * (1 + HL_RATIO) + + if 'ema': + LOWER = EMA(LOW, length) + MID = EMA(close, length) + UPPER = EMA(HIGH, length) + else: + LOWER = SMA(LOW, length) + MID = SMA(close, length) + UPPER = SMA(HIGH, length) + +Args: + high (pd.Series): Series of 'high's + low (pd.Series): Series of 'low's + 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' + drift (int): The difference period. Default: 1 + 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. +""" \ No newline at end of file diff --git a/pandas_ta/volatility/atr.py b/pandas_ta/volatility/atr.py new file mode 100644 index 0000000..e56495a --- /dev/null +++ b/pandas_ta/volatility/atr.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +from .true_range import true_range +from ..utils import get_drift, get_offset, verify_series + +def atr(high, low, close, length=None, mamode=None, drift=None, offset=None, **kwargs): + """Indicator: Average True Range (ATR)""" + # Validate arguments + high = verify_series(high) + low = verify_series(low) + close = verify_series(close) + length = int(length) if length and length > 0 else 14 + min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + mamode = mamode.lower() if mamode else 'ema' + drift = get_drift(drift) + offset = get_offset(offset) + + # Calculate Result + tr = true_range(high=high, low=low, close=close, drift=drift) + if mamode == 'ema': + atr = tr.ewm(span=length, min_periods=min_periods).mean() + else: + atr = tr.rolling(length, min_periods=min_periods).mean() + + # Offset + if offset != 0: + atr = atr.shift(offset) + + # Handle fills + if 'fillna' in kwargs: + atr.fillna(kwargs['fillna'], inplace=True) + if 'fill_method' in kwargs: + atr.fillna(method=kwargs['fill_method'], inplace=True) + + # Name and Categorize it + atr.name = f"ATR_{length}" + atr.category = 'volatility' + + return atr + + + +atr.__doc__ = \ +"""Average True Range (ATR) + +Averge True Range is used to measure volatility, especially +volatility caused by gaps or limit moves. + +Sources: + https://www.tradingview.com/wiki/Average_True_Range_(ATR) + +Calculation: + Default Inputs: + length=14, drift=1 + SMA = Simple Moving Average + EMA = Exponential Moving Average + TR = True Range + tr = TR(high, low, close, drift) + if 'ema': + ATR = EMA(tr, length) + else: + ATR = SMA(tr, length) + +Args: + high (pd.Series): Series of 'high's + low (pd.Series): Series of 'low's + close (pd.Series): Series of 'close's + length (int): It's period. Default: 14 + mamode (str): Two options: None or 'ema'. Default: 'ema' + drift (int): The difference period. Default: 1 + 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. +""" \ No newline at end of file diff --git a/pandas_ta/volatility/bbands.py b/pandas_ta/volatility/bbands.py new file mode 100644 index 0000000..148ba9c --- /dev/null +++ b/pandas_ta/volatility/bbands.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- +from pandas import DataFrame +from ..overlap import ema, sma +from ..statistics import stdev +from ..utils import get_offset, verify_series + +def bbands(close, length=None, std=None, mamode=None, offset=None, **kwargs): + """Indicator: Bollinger Bands (BBANDS)""" + # Validate arguments + close = verify_series(close) + length = int(length) if length and length > 0 else 20 + min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + std = float(std) if std and std > 0 else 2. + mamode = mamode.lower() if mamode else 'sma' + offset = get_offset(offset) + + # Calculate Result + standard_deviation = stdev(close=close, length=length) + deviations = std * standard_deviation + + if mamode is None or mamode == 'sma': + mid = sma(close=close, length=length) + elif mamode == 'ema': + mid = ema(close=close, length=length, **kwargs) + + lower = mid - deviations + upper = mid + deviations + + # Offset + if offset != 0: + lower = lower.shift(offset) + mid = mid.shift(offset) + upper = upper.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) + 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) + + # Name and Categorize it + lower.name = f"BBL_{length}" + mid.name = f"BBM_{length}" + upper.name = f"BBU_{length}" + mid.category = upper.category = lower.category = 'volatility' + + # Prepare DataFrame to return + data = {lower.name: lower, mid.name: mid, upper.name: upper} + bbandsdf = DataFrame(data) + bbandsdf.name = f"BBANDS_{length}" + bbandsdf.category = 'volatility' + + return bbandsdf + + + +bbands.__doc__ = \ +"""Bollinger Bands (BBANDS) + +A popular volatility indicator. + +Sources: + https://www.tradingview.com/wiki/Bollinger_Bands_(BB) + +Calculation: + Default Inputs: + length=20, std=2 + EMA = Exponential Moving Average + SMA = Simple Moving Average + STDEV = Standard Deviation + stdev = STDEV(close, length) + if 'ema': + MID = EMA(close, length) + else: + MID = SMA(close, length) + + LOWER = MID - std * stdev + UPPER = MID + std * stdev + +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: None 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. +""" \ No newline at end of file diff --git a/pandas_ta/volatility/donchian.py b/pandas_ta/volatility/donchian.py new file mode 100644 index 0000000..7e892a9 --- /dev/null +++ b/pandas_ta/volatility/donchian.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +from pandas import DataFrame +from ..utils import get_offset, verify_series + +def donchian(close, lower_length=None, upper_length=None, offset=None, **kwargs): + """Indicator: Donchian Channels (DC)""" + # Validate arguments + close = verify_series(close) + lower_length = int(lower_length) if lower_length and lower_length > 0 else 10 + upper_length = int(upper_length) if upper_length and upper_length > 0 else 20 + lower_min_periods = int(kwargs['lower_min_periods']) if 'lower_min_periods' in kwargs and kwargs['lower_min_periods'] is not None else lower_length + upper_min_periods = int(kwargs['upper_min_periods']) if 'upper_min_periods' in kwargs and kwargs['upper_min_periods'] is not None else upper_length + offset = get_offset(offset) + + # Calculate Result + lower = close.rolling(lower_length, min_periods=lower_min_periods).min() + upper = close.rolling(upper_length, min_periods=upper_min_periods).max() + mid = 0.5 * (lower + upper) + + # Handle fills + if 'fillna' in kwargs: + lower.fillna(kwargs['fillna'], inplace=True) + mid.fillna(kwargs['fillna'], inplace=True) + upper.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) + + # Offset + if offset != 0: + lower = lower.shift(offset) + mid = mid.shift(offset) + upper = upper.shift(offset) + + # Name and Categorize it + lower.name = f"DCL_{lower_length}_{upper_length}" + mid.name = f"DCM_{lower_length}_{upper_length}" + upper.name = f"DCU_{lower_length}_{upper_length}" + mid.category = upper.category = lower.category = 'volatility' + + # Prepare DataFrame to return + data = {lower.name: lower, mid.name: mid, upper.name: upper} + dcdf = DataFrame(data) + dcdf.name = f"DC_{lower_length}_{upper_length}" + dcdf.category = 'volatility' + + return dcdf + + + +donchian.__doc__ = \ +"""Donchian Channels (DC) + +Donchian Channels are used to measure volatility, similar to +Bollinger Bands and Keltner Channels. + +Sources: + https://www.tradingview.com/wiki/Donchian_Channels_(DC) + +Calculation: + Default Inputs: + length=20 + LOWER = close.rolling(length).min() + UPPER = close.rolling(length).max() + MID = 0.5 * (LOWER + UPPER) + +Args: + close (pd.Series): Series of 'close's + length (int): The short period. Default: 20 + 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. +""" \ No newline at end of file diff --git a/pandas_ta/volatility/kc.py b/pandas_ta/volatility/kc.py new file mode 100644 index 0000000..23c4279 --- /dev/null +++ b/pandas_ta/volatility/kc.py @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- +from numpy import sqrt as npsqrt +from pandas import DataFrame +from .atr import atr +from ..overlap import hlc3 +from ..statistics import variance +from ..utils import get_offset, verify_series + + +def kc(high, low, close, length=None, scalar=None, mamode=None, offset=None, **kwargs): + """Indicator: Keltner Channels (KC)""" + # Validate arguments + high = verify_series(high) + low = verify_series(low) + close = verify_series(close) + length = int(length) if length and length > 0 else 20 + min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + scalar = float(scalar) if scalar and scalar > 0 else 2 + mamode = mamode.lower() if mamode else None + offset = get_offset(offset) + + # Calculate Result + std = variance(close=close, length=length).apply(npsqrt) + + if mamode == 'ema': + basis = close.ewm(span=length, min_periods=min_periods).mean() + band = atr(high=high, low=low, close=close) + else: + hl_range = high - low + typical_price = hlc3(high=high, low=low, close=close) + basis = typical_price.rolling(length, min_periods=min_periods).mean() + band = hl_range.rolling(length, min_periods=min_periods).mean() + + lower = basis - scalar * band + upper = basis + scalar * band + + # Offset + if offset != 0: + lower = lower.shift(offset) + basis = basis.shift(offset) + upper = upper.shift(offset) + + # Handle fills + if 'fillna' in kwargs: + lower.fillna(kwargs['fillna'], inplace=True) + basis.fillna(kwargs['fillna'], inplace=True) + upper.fillna(kwargs['fillna'], inplace=True) + if 'fill_method' in kwargs: + lower.fillna(method=kwargs['fill_method'], inplace=True) + basis.fillna(method=kwargs['fill_method'], inplace=True) + upper.fillna(method=kwargs['fill_method'], inplace=True) + + # Name and Categorize it + lower.name = f"KCL_{length}" + basis.name = f"KCB_{length}" + upper.name = f"KCU_{length}" + basis.category = upper.category = lower.category = 'volatility' + + # Prepare DataFrame to return + data = {lower.name: lower, basis.name: basis, upper.name: upper} + kcdf = DataFrame(data) + kcdf.name = f"KC_{length}" + kcdf.category = 'volatility' + + return kcdf + + + +kc.__doc__ = \ +"""Keltner Channels (KC) + +A popular volatility indicator similar to Bollinger Bands and +Donchian Channels. + +Sources: + https://www.tradingview.com/wiki/Keltner_Channels_(KC) + +Calculation: + Default Inputs: + length=20, scalar=2 + ATR = Average True Range + EMA = Exponential Moving Average + SMA = Simple Moving Average + if 'ema': + BASIS = EMA(close, length) + BAND = ATR(high, low, close) + else: + hl_range = high - low + tp = typical_price = hlc3(high, low, close) + BASIS = SMA(tp, length) + BAND = SMA(hl_range, length) + + LOWER = BASIS - scalar * BAND + UPPER = BASIS + scalar * BAND + +Args: + high (pd.Series): Series of 'high's + low (pd.Series): Series of 'low's + 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: None 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, basis, upper columns. +""" \ No newline at end of file diff --git a/pandas_ta/volatility/massi.py b/pandas_ta/volatility/massi.py new file mode 100644 index 0000000..c63b8a0 --- /dev/null +++ b/pandas_ta/volatility/massi.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +from ..overlap import ema +from ..utils import get_offset, verify_series + +def massi(high, low, fast=None, slow=None, offset=None, **kwargs): + """Indicator: Mass Index (MASSI)""" + # Validate arguments + high = verify_series(high) + low = verify_series(low) + fast = int(fast) if fast and fast > 0 else 9 + slow = int(slow) if slow and slow > 0 else 25 + if slow < fast: + fast, slow = slow, fast + min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else fast + offset = get_offset(offset) + + # Calculate Result + hl_range = high - low + hl_ema1 = ema(close=hl_range, length=fast, **kwargs) + hl_ema2 = ema(close=hl_ema1, length=fast, **kwargs) + + hl_ratio = hl_ema1 / hl_ema2 + massi = hl_ratio.rolling(slow, min_periods=slow).sum() + + # Offset + if offset != 0: + massi = massi.shift(offset) + + # Handle fills + if 'fillna' in kwargs: + massi.fillna(kwargs['fillna'], inplace=True) + if 'fill_method' in kwargs: + massi.fillna(method=kwargs['fill_method'], inplace=True) + + # Name and Categorize it + massi.name = f"MASSI_{fast}_{slow}" + massi.category = 'volatility' + + return massi + + + +massi.__doc__ = \ +"""Mass Index (MASSI) + +The Mass Index is a non-directional volatility indicator that utilitizes the +High-Low Range to identify trend reversals based on range expansions. + +Sources: + https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:mass_index + mi = sum(ema(high - low, 9) / ema(ema(high - low, 9), 9), length) + +Calculation: + Default Inputs: + fast: 9, slow: 25 + EMA = Exponential Moving Average + hl = high - low + hl_ema1 = EMA(hl, fast) + hl_ema2 = EMA(hl_ema1, fast) + hl_ratio = hl_ema1 / hl_ema2 + MASSI = SUM(hl_ratio, slow) + +Args: + high (pd.Series): Series of 'high's + low (pd.Series): Series of 'low's + fast (int): The short period. Default: 9 + slow (int): The long period. Default: 25 + 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. +""" \ No newline at end of file diff --git a/pandas_ta/volatility/natr.py b/pandas_ta/volatility/natr.py new file mode 100644 index 0000000..e8b539d --- /dev/null +++ b/pandas_ta/volatility/natr.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +from .atr import atr +from ..utils import get_drift, get_offset, verify_series + +def natr(high, low, close, length=None, mamode=None, drift=None, offset=None, **kwargs): + """Indicator: Normalized Average True Range (NATR)""" + # Validate arguments + high = verify_series(high) + low = verify_series(low) + close = verify_series(close) + length = int(length) if length and length > 0 else 14 + mamode = mamode.lower() if mamode else 'ema' + drift = get_drift(drift) + offset = get_offset(offset) + + # Calculate Result + natr = (100 / close) * atr(high=high, low=low, close=close, length=length, mamode=mamode, drift=drift, offset=offset, **kwargs) + + # Offset + if offset != 0: + natr = natr.shift(offset) + + # Handle fills + if 'fillna' in kwargs: + natr.fillna(kwargs['fillna'], inplace=True) + if 'fill_method' in kwargs: + natr.fillna(method=kwargs['fill_method'], inplace=True) + + # Name and Categorize it + natr.name = f"NATR_{length}" + natr.category = 'volatility' + + return natr + + + +natr.__doc__ = \ +"""Normalized Average True Range (NATR) + +Normalized Average True Range attempt to normalize the average +true range. + +Sources: + https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/normalized-average-true-range-natr/ + +Calculation: + Default Inputs: + length=20 + ATR = Average True Range + NATR = (100 / close) * ATR(high, low, close) + +Args: + high (pd.Series): Series of 'high's + low (pd.Series): Series of 'low's + close (pd.Series): Series of 'close's + length (int): The short period. Default: 20 + 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 +""" \ No newline at end of file diff --git a/pandas_ta/volatility/true_range.py b/pandas_ta/volatility/true_range.py new file mode 100644 index 0000000..b300fa9 --- /dev/null +++ b/pandas_ta/volatility/true_range.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +from pandas import DataFrame +from ..utils import get_drift, get_offset, verify_series + +def true_range(high, low, close, drift=None, offset=None, **kwargs): + """Indicator: True Range""" + # Validate arguments + high = verify_series(high) + low = verify_series(low) + close = verify_series(close) + drift = get_drift(drift) + offset = get_offset(offset) + + # Calculate Result + prev_close = close.shift(drift) + ranges = [high - low, high - prev_close, low - prev_close] + true_range = DataFrame(ranges).T + true_range = true_range.abs().max(axis=1) + + # Offset + if offset != 0: + true_range = true_range.shift(offset) + + # Handle fills + if 'fillna' in kwargs: + true_range.fillna(kwargs['fillna'], inplace=True) + if 'fill_method' in kwargs: + true_range.fillna(method=kwargs['fill_method'], inplace=True) + + # Name and Categorize it + true_range.name = f"TRUERANGE_{drift}" + true_range.category = 'volatility' + + return true_range + + + +true_range.__doc__ = \ +"""True Range + +An method to expand a classical range (high minus low) to include +possible gap scenarios. + +Sources: + https://www.macroption.com/true-range/ + +Calculation: + Default Inputs: + drift=1 + ABS = Absolute Value + prev_close = close.shift(drift) + TRUE_RANGE = ABS([high - low, high - prev_close, low - prev_close]) + +Args: + high (pd.Series): Series of 'high's + low (pd.Series): Series of 'low's + close (pd.Series): Series of 'close's + drift (int): The shift period. Default: 1 + 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 +""" \ No newline at end of file diff --git a/setup.py b/setup.py index 2a166f8..91965cd 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ long_description = "An easy to use Python 3 Pandas Extension of Technical Analys setup( name = "pandas_ta", packages = ["pandas_ta"], - version = "0.1.21b", + version = "0.1.22b", description=long_description, long_description=long_description, author = "Kevin Johnson", diff --git a/tests/test_indicator_volatility.py b/tests/test_indicator_volatility.py index 2327a2c..3e6a1a6 100644 --- a/tests/test_indicator_volatility.py +++ b/tests/test_indicator_volatility.py @@ -30,20 +30,17 @@ class TestVolatility(TestCase): del cls.data - def setUp(self): - self.volatility = pandas_ta.volatility - - def tearDown(self): - del self.volatility + def setUp(self): pass + def tearDown(self): pass def test_accbands(self): - result = self.volatility.accbands(self.high, self.low, self.close) + result = pandas_ta.accbands(self.high, self.low, self.close) self.assertIsInstance(result, DataFrame) self.assertEqual(result.name, 'ACCBANDS_20') def test_atr(self): - result = self.volatility.atr(self.high, self.low, self.close) + result = pandas_ta.atr(self.high, self.low, self.close) self.assertIsInstance(result, Series) self.assertEqual(result.name, 'ATR_14') @@ -58,7 +55,7 @@ class TestVolatility(TestCase): error_analysis(result, CORRELATION, ex) def test_bbands(self): - result = self.volatility.bbands(self.close) + result = pandas_ta.bbands(self.close) self.assertIsInstance(result, DataFrame) self.assertEqual(result.name, 'BBANDS_20') @@ -86,27 +83,27 @@ class TestVolatility(TestCase): error_analysis(result.iloc[:,2], CORRELATION, ex, newline=False) def test_donchian(self): - result = self.volatility.donchian(self.close) + result = pandas_ta.donchian(self.close) self.assertIsInstance(result, DataFrame) self.assertEqual(result.name, 'DC_10_20') - result = self.volatility.donchian(self.close, lower_length=20, upper_length=5) + result = pandas_ta.donchian(self.close, lower_length=20, upper_length=5) self.assertIsInstance(result, DataFrame) self.assertEqual(result.name, 'DC_20_5') def test_kc(self): - result = self.volatility.kc(self.high, self.low, self.close) + result = pandas_ta.kc(self.high, self.low, self.close) self.assertIsInstance(result, DataFrame) self.assertEqual(result.name, 'KC_20') def test_massi(self): - result = self.volatility.massi(self.high, self.low) + result = pandas_ta.massi(self.high, self.low) self.assertIsInstance(result, Series) self.assertEqual(result.name, 'MASSI_9_25') def test_natr(self): - result = self.volatility.natr(self.high, self.low, self.close) + result = pandas_ta.natr(self.high, self.low, self.close) self.assertIsInstance(result, Series) self.assertEqual(result.name, 'NATR_14') @@ -121,7 +118,7 @@ class TestVolatility(TestCase): error_analysis(result, CORRELATION, ex) def test_true_range(self): - result = self.volatility.true_range(self.high, self.low, self.close) + result = pandas_ta.true_range(self.high, self.low, self.close) self.assertIsInstance(result, Series) self.assertEqual(result.name, 'TRUERANGE_1') diff --git a/tests/test_indicator_volatility_ext.py b/tests/test_indicator_volatility_ext.py index 71053aa..6fd4dea 100644 --- a/tests/test_indicator_volatility_ext.py +++ b/tests/test_indicator_volatility_ext.py @@ -16,11 +16,8 @@ class TestVolatilityExtension(TestCase): del cls.data - def setUp(self): - pass - - def tearDown(self): - pass + def setUp(self): pass + def tearDown(self): pass def test_accbands_ext(self): @@ -31,6 +28,8 @@ class TestVolatilityExtension(TestCase): def test_atr_ext(self): self.data.ta.atr(append=True) self.assertIsInstance(self.data, DataFrame) + print() + print(self.data[self.data.columns[-1]].tail()) self.assertEqual(self.data.columns[-1], 'ATR_14') def test_bbands_ext(self): @@ -61,4 +60,6 @@ class TestVolatilityExtension(TestCase): def test_true_range_ext(self): self.data.ta.true_range(append=True) self.assertIsInstance(self.data, DataFrame) + print() + print(self.data[self.data.columns[-1]].tail()) self.assertEqual(self.data.columns[-1], 'TRUERANGE_1') \ No newline at end of file