diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pandas_ta/core.py b/pandas_ta/core.py index 7d6fe99..3a229db 100644 --- a/pandas_ta/core.py +++ b/pandas_ta/core.py @@ -910,7 +910,17 @@ class AnalysisIndicators(BasePandasObject): result = dpo(close=close, length=length, centered=centered, offset=offset, **kwargs) return result - @finalize + def ha(self, open=None, high=None, low=None, close=None, offset=None, **kwargs): + open = self._get_column(open, 'open') + high = self._get_column(high, 'high') + low = self._get_column(low, 'low') + close = self._get_column(close, 'close') + + result = ha(open=open, high=high, low=low, close=close, offset=offset, **kwargs) + self._add_prefix_suffix(result, **kwargs) + self._append(result, **kwargs) + return result + def increasing(self, close=None, length=None, asint=True, offset=None, **kwargs): close = self._get_column(close, 'close') @@ -966,6 +976,18 @@ class AnalysisIndicators(BasePandasObject): self._append(result, **kwargs) return result + def supertrend(self, high=None, low=None, close=None, period=None, multiplier=None, mamode=None, drift=None, + offset=None, **kwargs): + high = self._get_column(high, 'high') + low = self._get_column(low, 'low') + close = self._get_column(close, 'close') + + result = supertrend(high=high, low=low, close=close, period=period, multiplier=multiplier, mamode=mamode, drift=drift, offset=offset, **kwargs) + self._add_prefix_suffix(result, **kwargs) + self._append(result, **kwargs) + return result + + @finalize def vortex(self, high=None, low=None, close=None, drift=None, offset=None, **kwargs): high = self._get_column(high, 'high') diff --git a/pandas_ta/momentum/stoch.py b/pandas_ta/momentum/stoch.py index 4da6a0a..7cdb1f1 100644 --- a/pandas_ta/momentum/stoch.py +++ b/pandas_ta/momentum/stoch.py @@ -48,6 +48,7 @@ def stoch(high, low, close, fast_k=None, slow_k=None, slow_d=None, offset=None, fastd.name = f"STOCHFd_{slow_d}" slowk.name = f"STOCHk_{slow_k}" slowd.name = f"STOCHd_{slow_d}" + fastk.category = fastd.category = slowk.category = slowd.category = 'momentum' # Prepare DataFrame to return @@ -98,4 +99,4 @@ Kwargs: Returns: pd.DataFrame: fastk, fastd, slowk, slowd columns. -""" \ No newline at end of file +""" diff --git a/pandas_ta/trend/__init__.py b/pandas_ta/trend/__init__.py index dbdce91..f98b9da 100644 --- a/pandas_ta/trend/__init__.py +++ b/pandas_ta/trend/__init__.py @@ -6,10 +6,12 @@ from .chop import chop from .cksp import cksp from .decreasing import decreasing from .dpo import dpo +from .ha import ha from .increasing import increasing from .linear_decay import linear_decay from .long_run import long_run from .psar import psar from .qstick import qstick from .short_run import short_run +from .supertrend import supertrend from .vortex import vortex \ No newline at end of file diff --git a/pandas_ta/trend/ha.py b/pandas_ta/trend/ha.py new file mode 100644 index 0000000..d72e4ce --- /dev/null +++ b/pandas_ta/trend/ha.py @@ -0,0 +1,99 @@ +# -*- coding: utf-8 -*- +import numpy as np +from pandas import DataFrame +from pandas_ta.utils import get_offset, verify_series + + +def ha(open, high, low, close, offset=None, **kwargs): + # indicator : Heikin Ashi + # Validate Arguments + open_ = verify_series(open) + high = verify_series(high) + low = verify_series(low) + close = verify_series(close) + offset = get_offset(offset) + + # calculate ha_close + ha_close = 0.25 * (open_ + high + low + close) + + # Initialization of the ha_open array + ha_open = np.zeros(shape=(len(close))) + + # ha_open of the first element + ha_open[0] = 0.5 * (open_[0] + close[0]) + + # calculate ha_open. Based on previous ha_open & ha_close + for i in range(1, len(close)): + ha_open[i] = 0.5 * (ha_open[i-1] + ha_close[i-1]) + + # calculation of ha_high & ha_low + ha_high = np.maximum.reduce([high, ha_open, ha_close]) + ha_low = np.minimum.reduce([low, ha_open, ha_close]) + + # Prepare DataFrame to return + data = {'ha_open': ha_open, 'ha_high': ha_high, 'ha_low': ha_low, 'ha_close': ha_close} + hadf = DataFrame(data) + hadf.name = "Heikin-Ashi" + hadf.category = 'trend' + + # Apply offset if needed + if offset != 0: + hadf = hadf.shift(offset) + + # Handle fills + if 'fillna' in kwargs: + hadf.fillna(kwargs['fillna'], inplace=True) + + if 'fill_method' in kwargs: + hadf.fillna(method=kwargs['fill_method'], inplace=True) + + return hadf + + +ha.__doc__ = \ +"""Heikin Ashi (HA) + +The Heikin-Ashi technique averages price data to create a Japanese candlestick chart that filters out market noise. +Heikin-Ashi charts, developed by Munehisa Homma in the 1700s, +share some characteristics with standard candlestick charts but differ based on the values used to create each candle. +Instead of using the open, high, low, and close like standard candlestick charts, +the Heikin-Ashi technique uses a modified formula based on two-period averages. +This gives the chart a smoother appearance, making it easier to spots trends and reversals, +but also obscures gaps and some price data. + +Sources: + https://www.investopedia.com/terms/h/heikinashi.asp + +Calculation: + The Formula for the Heikin-Ashi technique is: + +Heikin-Ashi Close=(Open0+High0+Low0+Close0)/4 +Heikin-Ashi Open=(HA Open−1+HA Close−1)/2 +Heikin-Ashi High=Max (High0,HA Open0,HA Close0) +Heikin-Ashi Low=Min (Low0,HA Open0,HA Close0) +where:Open0 etc.=Values from the current period +Open−1 etc.=Values from the prior period +HA=Heikin-Ashi + + How to Calculate Heikin-Ashi + + Use one period to create the first Heikin-Ashi (HA) candle, using the formulas. + For example use the high, low, open, and close to create the first HA close price. + Use the open and close to create the first HA open. + The high of the period will be the first HA high, and the low will be the first HA low. + With the first HA calculated, it is now possible to continue computing the HA candles per the formulas. +​​ +Args: + open_ (pd.Series): Series of 'open's + high (pd.Series): Series of 'high's + low (pd.Series): Series of 'low's + close (pd.Series): Series of 'close's + + +Kwargs: + fillna (value, optional): pd.DataFrame.fillna(value) + fill_method (value, optional): Type of fill method + +Returns: + pd.DataFrame: ha_open, ha_high,ha_low, ha_close columns. +""" diff --git a/pandas_ta/trend/supertrend.py b/pandas_ta/trend/supertrend.py new file mode 100644 index 0000000..bf5ccee --- /dev/null +++ b/pandas_ta/trend/supertrend.py @@ -0,0 +1,104 @@ +# -*- coding: utf-8 -*- +import numpy as np +from pandas import DataFrame +from ..utils import get_offset, verify_series +from ..volatility import atr + + +def supertrend(high, low, close, length=None, multiplier=None, mamode=None, drift=None, offset=None, **kwargs): + # indicator : supertrend + # Validate Arguments + high = verify_series(high) + low = verify_series(low) + close = verify_series(close) + offset = get_offset(offset) + length = int(length) if length and length > 0 else 10 + multiplier = float(multiplier) if multiplier and multiplier > 0 else 3 + min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs[ + 'min_periods'] is not None else length + + supertrend_dir = np.zeros(shape=(len(close))) + strend = np.zeros(shape=(len(close))) + + # Bands initial calculation + midrange = 0.5 * (high + low) + distance = multiplier * atr(high, low, close, length, mamode, drift, offset, min_periods=min_periods) + lowerband = midrange - distance + upperband = midrange + distance + + # final calculation loop + for i in range(1, len(close)): + if close[i] > upperband[i - 1]: + supertrend_dir[i] = 1 + elif close[i] < lowerband[i - 1]: + supertrend_dir[i] = -1 + else: + supertrend_dir[i] = supertrend_dir[i - 1] + if supertrend_dir[i] > 0 and lowerband[i] < lowerband[i - 1]: + lowerband[i] = lowerband[i - 1] + if supertrend_dir[i] < 0 and upperband[i] > upperband[i - 1]: + upperband[i] = upperband[i - 1] + if supertrend_dir[i] < 0: + strend[i] = upperband[i] + else: + strend[i] = lowerband[i] + + # Prepare DataFrame to return + data = {f"supertrend_{length}_{multiplier}": strend, f"supertrend_dir_{length}_{multiplier}": supertrend_dir} + supertrend_df = DataFrame(data) + supertrend_df.name = f"supertrend_{length}_{multiplier}" + supertrend_df.category = 'trend' + + # Apply offset if needed + if offset != 0: + supertrend_df = supertrend_df.shift(offset) + + # Handle fills + if 'fillna' in kwargs: + supertrend_df.fillna(kwargs['fillna'], inplace=True) + + if 'fill_method' in kwargs: + supertrend_df.fillna(method=kwargs['fill_method'], inplace=True) + + return supertrend_df + + +supertrend.__doc__ = \ + """Supertrend (supertrend) + +Supertrend is a trend indicator. It is usually used to help identify trend direction, setting stop loss, +identify support and resistance, and / or generate buy & sell signals. +Calculation is in 2 steps : first a multiple of ATR is added and substracted to the middle of the high - low range. +This gives the upperband and lowerband. +The direction of the trend is then calculated : if close > previous upperband or < previous lowerband, +then trend direction is changed, else it is the same as previous value. +If trend direction is unchanged and down, upperband is set to minimum between current and previous value +If trend direction is unchanged and up, lowerband is set to maximum between current and previous value. + +The final band is then choosen according to the direction of the trend : upperband if trend is downward, +lowerband if trend is upward. +Returned values are : float for final band level, int (1 : upward trend, -1 : downward trend) for trend direction + +Calculation: + Default Inputs: + length = 10 + multiplier = 3 + +Args: + high (pd.Series): Series of 'high's + low (pd.Series): Series of 'low's + close (pd.Series): Series of 'close's + length (int) : length for ATR calculation. Default : 10 + multiplier : coefficient for upper and lower band distance to midrange. Default : 3 + mamode: parameter used for ATR calculation. See ATR documentation. Default : None (= ema) + drift : parameter used for ATR calculation. See ATR documentation. Default : None (= 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 + min_periods (int, optional) : parameter used for ATR calculation. See ATR documentation. Default : length + +Returns: + pd.DataFrame: supertrend (float), supertrend_dir (int) columns. +""" diff --git a/pandas_ta/volatility/atr.py b/pandas_ta/volatility/atr.py index c6474da..bd2ab80 100644 --- a/pandas_ta/volatility/atr.py +++ b/pandas_ta/volatility/atr.py @@ -75,6 +75,7 @@ Args: Kwargs: fillna (value, optional): pd.DataFrame.fillna(value) fill_method (value, optional): Type of fill method + min_periods (int, optional) : Minimum number of periods before calculating ATR. Default : length Returns: pd.Series: New feature generated.