Files
pandas-ta/pandas_ta/volatility/kc.py
T
2019-05-20 13:25:33 -07:00

111 lines
3.5 KiB
Python

# -*- coding: utf-8 -*-
from numpy import sqrt as npsqrt
from pandas import DataFrame
from .atr import atr
from ..overlap.hlc3 import hlc3
from ..statistics.variance 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.
"""