def obv(close, volume, offset=None, **kwargs): """Indicator: On Balance Volume (OBV)""" # Validate arguments close = verify_series(close) volume = verify_series(volume) offset = get_offset(offset) # Calculate Result signed_volume = signed_series(close, initial=1) * volume obv = signed_volume.cumsum() # Offset if offset != 0: obv = obv.shift(offset) # Handle fills if "fillna" in kwargs: obv.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: obv.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it obv.name = f"OBV" obv.category = "volume" return obv
def obv(close, volume, talib=None, offset=None, **kwargs): """Indicator: On Balance Volume (OBV)""" # Validate arguments close = verify_series(close) volume = verify_series(volume) offset = get_offset(offset) mode_tal = bool(talib) if isinstance(talib, bool) else True # Calculate Result if Imports["talib"] and mode_tal: from talib import OBV obv = OBV(close, volume) else: signed_volume = signed_series(close, initial=1) * volume obv = signed_volume.cumsum() # Offset if offset != 0: obv = obv.shift(offset) # Handle fills if "fillna" in kwargs: obv.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: obv.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it obv.name = f"OBV" obv.category = "volume" return obv
def midprice(high, low, length=None, offset=None, **kwargs): """Indicator: Midprice""" # Validate arguments high = verify_series(high) low = verify_series(low) length = int(length) if length and length > 0 else 2 min_periods = int( kwargs["min_periods"]) if "min_periods" in kwargs and kwargs[ "min_periods"] is not None else length offset = get_offset(offset) # Calculate Result lowest_low = low.rolling(length, min_periods=min_periods).min() highest_high = high.rolling(length, min_periods=min_periods).max() midprice = 0.5 * (lowest_low + highest_high) # Offset if offset != 0: midprice = midprice.shift(offset) # Handle fills if "fillna" in kwargs: midprice.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: midprice.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it midprice.name = f"MIDPRICE_{length}" midprice.category = "overlap" return midprice
def ad(high, low, close, volume, open_=None, offset=None, **kwargs): """Indicator: Accumulation/Distribution (AD)""" # Validate Arguments high = verify_series(high) low = verify_series(low) close = verify_series(close) volume = verify_series(volume) offset = get_offset(offset) # Calculate Result if open_ is not None: open_ = verify_series(open_) ad = non_zero_range(close, open_) # AD with Open else: ad = 2 * close - (high + low) # AD with High, Low, Close high_low_range = non_zero_range(high, low) ad *= volume / high_low_range ad = ad.cumsum() # Offset if offset != 0: ad = ad.shift(offset) # Handle fills if "fillna" in kwargs: ad.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: ad.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it ad.name = "AD" if open_ is None else "ADo" ad.category = "volume" return ad
def pgo(high, low, close, length=None, offset=None, **kwargs): """Indicator: Pretty Good Oscillator (PGO)""" # Validate arguments high = verify_series(high) low = verify_series(low) close = verify_series(close) length = int(length) if length and length > 0 else 14 offset = get_offset(offset) # Calculate Result pgo = close - sma(close, length) pgo /= ema(atr(high, low, close, length), length) # Offset if offset != 0: pgo = pgo.shift(offset) # Handle fills if "fillna" in kwargs: pgo.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: pgo.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it pgo.name = f"PGO_{length}" pgo.category = "momentum" return pgo
def cci(high, low, close, length=None, c=None, offset=None, **kwargs): """Indicator: Commodity Channel Index (CCI)""" # Validate Arguments high = verify_series(high) low = verify_series(low) close = verify_series(close) length = int(length) if length and length > 0 else 14 c = float(c) if c and c > 0 else 0.015 offset = get_offset(offset) # Calculate Result typical_price = hlc3(high=high, low=low, close=close) mean_typical_price = sma(typical_price, length=length) mad_typical_price = mad(typical_price, length=length) cci = typical_price - mean_typical_price cci /= c * mad_typical_price # Offset if offset != 0: cci = cci.shift(offset) # Handle fills if "fillna" in kwargs: cci.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: cci.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it cci.name = f"CCI_{length}_{c}" cci.category = "momentum" return cci
def cdl_inside(open_, high, low, close, asbool=False, offset=None, **kwargs): """Candle Type: Inside Bar""" # Validate arguments open_ = verify_series(open_) high = verify_series(high) low = verify_series(low) close = verify_series(close) offset = get_offset(offset) # Calculate Result inside = (high.diff() < 0) & (low.diff() > 0) if not asbool: inside *= candle_color(open_, close) # Offset if offset != 0: inside = inside.shift(offset) # Handle fills if "fillna" in kwargs: inside.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: inside.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it inside.name = f"CDL_INSIDE" inside.category = "candles" return inside
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 scalar = float(scalar) if scalar and scalar > 0 else 2 mamode = mamode.lower() if mamode else None offset = get_offset(offset) # Calculate Result use_tr = kwargs.pop("tr", True) if use_tr: range_ = true_range(high, low, close) else: range_ = high_low_range(high, low) _mode = "" if mamode == "sma": basis = sma(close, length) band = sma(range_, length=length) _mode += "s" elif mamode is None or mamode == "ema": basis = ema(close, length=length) band = ema(range_, length=length) 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 _props = f"{_mode if len(_mode) else ''}_{length}_{scalar}" lower.name = f"KCL{_props}" basis.name = f"KCB{_props}" upper.name = f"KCU{_props}" 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{_props}" kcdf.category = basis.category return kcdf
def pvi(close, volume, length=None, initial=None, offset=None, **kwargs): """Indicator: Positive Volume Index (PVI)""" # Validate arguments length = int(length) if length and length > 0 else 1 # min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length initial = int(initial) if initial and initial > 0 else 1000 close = verify_series(close, length) volume = verify_series(volume, length) offset = get_offset(offset) if close is None or volume is None: return # Calculate Result signed_volume = signed_series(volume, 1) pvi = roc(close=close, length=length) * signed_volume[signed_volume > 0].abs() pvi.fillna(0, inplace=True) pvi.iloc[0] = initial pvi = pvi.cumsum() # Offset if offset != 0: pvi = pvi.shift(offset) # Handle fills if "fillna" in kwargs: pvi.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: pvi.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it pvi.name = f"PVI_{length}" pvi.category = "volume" return pvi
def aroon(high, low, length=None, scalar=None, talib=None, offset=None, **kwargs): """Indicator: Aroon & Aroon Oscillator""" # Validate Arguments length = length if length and length > 0 else 14 scalar = float(scalar) if scalar else 100 high = verify_series(high, length) low = verify_series(low, length) offset = get_offset(offset) mode_tal = bool(talib) if isinstance(talib, bool) else True if high is None or low is None: return # Calculate Result if Imports["talib"] and mode_tal: from talib import AROON, AROONOSC aroon_down, aroon_up = AROON(high, low, length) aroon_osc = AROONOSC(high, low, length) else: periods_from_hh = high.rolling(length + 1).apply(recent_maximum_index, raw=True) periods_from_ll = low.rolling(length + 1).apply(recent_minimum_index, raw=True) aroon_up = aroon_down = scalar aroon_up *= 1 - (periods_from_hh / length) aroon_down *= 1 - (periods_from_ll / length) aroon_osc = aroon_up - aroon_down # Handle fills if "fillna" in kwargs: aroon_up.fillna(kwargs["fillna"], inplace=True) aroon_down.fillna(kwargs["fillna"], inplace=True) aroon_osc.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: aroon_up.fillna(method=kwargs["fill_method"], inplace=True) aroon_down.fillna(method=kwargs["fill_method"], inplace=True) aroon_osc.fillna(method=kwargs["fill_method"], inplace=True) # Offset if offset != 0: aroon_up = aroon_up.shift(offset) aroon_down = aroon_down.shift(offset) aroon_osc = aroon_osc.shift(offset) # Name and Categorize it aroon_up.name = f"AROONU_{length}" aroon_down.name = f"AROOND_{length}" aroon_osc.name = f"AROONOSC_{length}" aroon_down.category = aroon_up.category = aroon_osc.category = "trend" # Prepare DataFrame to return data = { aroon_down.name: aroon_down, aroon_up.name: aroon_up, aroon_osc.name: aroon_osc, } aroondf = DataFrame(data) aroondf.name = f"AROON_{length}" aroondf.category = aroon_down.category return aroondf
def hlc3(high, low, close, talib=None, offset=None, **kwargs): """Indicator: HLC3""" # Validate Arguments high = verify_series(high) low = verify_series(low) close = verify_series(close) offset = get_offset(offset) mode_tal = bool(talib) if isinstance(talib, bool) else True # Calculate Result if Imports["talib"] and mode_tal: from talib import TYPPRICE hlc3 = TYPPRICE(high, low, close) else: hlc3 = (high + low + close) / 3.0 # Offset if offset != 0: hlc3 = hlc3.shift(offset) # Name & Category hlc3.name = "HLC3" hlc3.category = "overlap" return hlc3
def pdist(open_, high, low, close, drift=None, offset=None, **kwargs): """Indicator: Price Distance (PDIST)""" # Validate Arguments open_ = verify_series(open_) high = verify_series(high) low = verify_series(low) close = verify_series(close) drift = get_drift(drift) offset = get_offset(offset) # Calculate Result pdist = 2 * non_zero_range(high, low) pdist += non_zero_range(open_, close.shift(drift)).abs() pdist -= non_zero_range(close, open_).abs() # Offset if offset != 0: pdist = pdist.shift(offset) # Handle fills if "fillna" in kwargs: pdist.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: pdist.fillna(method=kwargs["fill_method"], inplace=True) # Name & Category pdist.name = "PDIST" pdist.category = "volatility" return pdist
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) high_low_range = non_zero_range(high, 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 offset = get_offset(offset) if "length" in kwargs: kwargs.pop("length") # Calculate Result hl_ema1 = ema(close=high_low_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 long_run(fast, slow, length=None, offset=None, **kwargs): """Indicator: Long Run""" # Validate Arguments length = int(length) if length and length > 0 else 2 fast = verify_series(fast, length) slow = verify_series(slow, length) offset = get_offset(offset) if fast is None or slow is None: return # Calculate Result pb = increasing(fast, length) & decreasing( slow, length) # potential bottom or bottom bi = increasing(fast, length) & increasing( slow, length) # fast and slow are increasing long_run = pb | bi # Offset if offset != 0: long_run = long_run.shift(offset) # Handle fills if "fillna" in kwargs: long_run.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: long_run.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it long_run.name = f"LR_{length}" long_run.category = "trend" return long_run
def willr(high, low, close, length=None, offset=None, **kwargs): """Indicator: William's Percent R (WILLR)""" # 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 offset = get_offset(offset) # Calculate Result lowest_low = low.rolling(length, min_periods=min_periods).min() highest_high = high.rolling(length, min_periods=min_periods).max() willr = 100 * ((close - lowest_low) / (highest_high - lowest_low) - 1) # Offset if offset != 0: willr = willr.shift(offset) # Handle fills if "fillna" in kwargs: willr.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: willr.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it willr.name = f"WILLR_{length}" willr.category = "momentum" return willr
def pvt(close, volume, drift=None, offset=None, **kwargs): """Indicator: Price-Volume Trend (PVT)""" # Validate arguments close = verify_series(close) volume = verify_series(volume) drift = get_drift(drift) offset = get_offset(offset) # Calculate Result pv = roc(close=close, length=drift) * volume pvt = pv.cumsum() # Offset if offset != 0: pvt = pvt.shift(offset) # Handle fills if "fillna" in kwargs: pvt.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: pvt.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it pvt.name = f"PVT" pvt.category = "volume" return pvt
def brar(open_, high, low, close, length=None, scalar=None, drift=None, offset=None, **kwargs): """Indicator: BRAR (BRAR)""" # Validate Arguments open_ = verify_series(open_) high = verify_series(high) low = verify_series(low) close = verify_series(close) length = int(length) if length and length > 0 else 26 scalar = float(scalar) if scalar else 100 high_open_range = non_zero_range(high, open_) open_low_range = non_zero_range(open_, low) drift = get_drift(drift) offset = get_offset(offset) # Calculate Result hcy = non_zero_range(high, close.shift(drift)) cyl = non_zero_range(close.shift(drift), low) hcy[hcy < 0] = 0 # Zero negative values cyl[cyl < 0] = 0 # "" ar = scalar * high_open_range.rolling(length).sum() ar /= open_low_range.rolling(length).sum() br = scalar * hcy.rolling(length).sum() br /= cyl.rolling(length).sum() # Offset if offset != 0: ar = ar.shift(offset) br = ar.shift(offset) # Handle fills if "fillna" in kwargs: ar.fillna(kwargs["fillna"], inplace=True) br.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: ar.fillna(method=kwargs["fill_method"], inplace=True) br.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it _props = f"_{length}" ar.name = f"AR{_props}" br.name = f"BR{_props}" ar.category = br.category = "momentum" # Prepare DataFrame to return brardf = DataFrame({ar.name: ar, br.name: br}) brardf.name = f"BRAR{_props}" brardf.category = "momentum" return brardf
def short_run(fast, slow, length=None, offset=None, **kwargs): """Indicator: Short Run""" # Validate Arguments fast = verify_series(fast) slow = verify_series(slow) length = int(length) if length and length > 0 else 2 offset = get_offset(offset) # Calculate Result pt = decreasing(fast, length) & increasing(slow, length) # potential top or top bd = decreasing(fast, length) & decreasing( slow, length) # fast and slow are decreasing short_run = pt | bd # Offset if offset != 0: short_run = short_run.shift(offset) # Handle fills if "fillna" in kwargs: short_run.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: short_run.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it short_run.name = f"SR_{length}" short_run.category = "trend" return short_run
def bop(open_, high, low, close, scalar=None, offset=None, **kwargs): """Indicator: Balance of Power (BOP)""" # Validate Arguments open_ = verify_series(open_) high = verify_series(high) low = verify_series(low) close = verify_series(close) scalar = float(scalar) if scalar else 1 offset = get_offset(offset) # Calculate Result if Imports["talib"]: from talib import BOP bop = BOP(open_, high, low, close) else: high_low_range = non_zero_range(high, low) close_open_range = non_zero_range(close, open_) bop = scalar * close_open_range / high_low_range # Offset if offset != 0: bop = bop.shift(offset) # Handle fills if "fillna" in kwargs: bop.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: bop.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it bop.name = f"BOP" bop.category = "momentum" return bop
def natr(high, low, close, length=None, mamode=None, scalar=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" scalar = float(scalar) if scalar else 100 drift = get_drift(drift) offset = get_offset(offset) # Calculate Result natr = scalar / close natr *= 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 pvol(close, volume, offset=None, **kwargs): """Indicator: Price-Volume (PVOL)""" # Validate arguments close = verify_series(close) volume = verify_series(volume) offset = get_offset(offset) signed = kwargs.pop("signed", False) # Calculate Result if signed: pvol = signed_series(close, 1) * close * volume else: pvol = close * volume # Offset if offset != 0: pvol = pvol.shift(offset) # Handle fills if "fillna" in kwargs: pvol.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: pvol.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it pvol.name = f"PVOL" pvol.category = "volume" return pvol
def efi(close, volume, length=None, drift=None, mamode=None, offset=None, **kwargs): """Indicator: Elder's Force Index (EFI)""" # Validate arguments close = verify_series(close) volume = verify_series(volume) length = int(length) if length and length > 0 else 13 drift = get_drift(drift) mamode = mamode if isinstance(mamode, str) else "ema" offset = get_offset(offset) # Calculate Result pv_diff = close.diff(drift) * volume efi = ma(mamode, pv_diff, length=length) # Offset if offset != 0: efi = efi.shift(offset) # Handle fills if "fillna" in kwargs: efi.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: efi.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it efi.name = f"EFI_{length}" efi.category = "volume" return efi
def vwap(high, low, close, volume, offset=None, **kwargs): """Indicator: Volume Weighted Average Price (VWAP)""" # Validate Arguments high = verify_series(high) low = verify_series(low) close = verify_series(close) volume = verify_series(volume) offset = get_offset(offset) typical_price = hlc3(high=high, low=low, close=close) if not is_datetime_ordered(volume): print( f"[!] VWAP volume series is not datetime ordered. Results may not be as expected." ) if not is_datetime_ordered(typical_price): print( f"[!] VWAP price series is not datetime ordered. Results may not be as expected." ) # Calculate Result weighted_price = typical_price * volume vwap = weighted_price.groupby(weighted_price.index.to_period('d')).cumsum() / \ volume.groupby(volume.index.to_period('d')).cumsum() # Offset if offset != 0: vwap = vwap.shift(offset) # Name & Category vwap.name = "VWAP" vwap.category = 'overlap' return vwap
def ao(high, low, fast=None, slow=None, offset=None, **kwargs): """Indicator: Awesome Oscillator (AO)""" # Validate Arguments high = verify_series(high) low = verify_series(low) fast = int(fast) if fast and fast > 0 else 5 slow = int(slow) if slow and slow > 0 else 34 if slow < fast: fast, slow = slow, fast offset = get_offset(offset) # Calculate Result median_price = 0.5 * (high + low) fast_sma = sma(median_price, fast) slow_sma = sma(median_price, slow) ao = fast_sma - slow_sma # Offset if offset != 0: ao = ao.shift(offset) # Handle fills if "fillna" in kwargs: ao.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: ao.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it ao.name = f"AO_{fast}_{slow}" ao.category = "momentum" return ao
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 high_low_range = non_zero_range(high, low) prev_close = close.shift(drift) ranges = [high_low_range, high - prev_close, prev_close - low] true_range = concat(ranges, axis=1) true_range = true_range.abs().max(axis=1) true_range.iloc[:drift] = npNaN # 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
def vwma(close, volume, length=None, offset=None, **kwargs): """Indicator: Volume Weighted Moving Average (VWMA)""" # Validate Arguments length = int(length) if length and length > 0 else 10 close = verify_series(close, length) volume = verify_series(volume, length) offset = get_offset(offset) if close is None or volume is None: return # Calculate Result pv = close * volume vwma = sma(close=pv, length=length) / sma(close=volume, length=length) # Offset if offset != 0: vwma = vwma.shift(offset) # Handle fills if "fillna" in kwargs: vwma.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: vwma.fillna(method=kwargs["fill_method"], inplace=True) # Name & Category vwma.name = f"VWMA_{length}" vwma.category = "overlap" return vwma
def wcp(high, low, close, offset=None, **kwargs): """Indicator: Weighted Closing Price (WCP)""" # Validate Arguments high = verify_series(high) low = verify_series(low) close = verify_series(close) offset = get_offset(offset) # Calculate Result if Imports["talib"]: from talib import WCLPRICE wcp = WCLPRICE(high, low, close) else: wcp = (high + low + 2 * close) / 4 # Offset if offset != 0: wcp = wcp.shift(offset) # Handle fills if "fillna" in kwargs: wcp.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: wcp.fillna(method=kwargs["fill_method"], inplace=True) # Name & Category wcp.name = "WCP" wcp.category = "overlap" return wcp
def nvi(close, volume, length=None, initial=None, offset=None, **kwargs): """Indicator: Negative Volume Index (NVI)""" # Validate arguments close = verify_series(close) volume = verify_series(volume) length = int(length) if length and length > 0 else 1 min_periods = int( kwargs["min_periods"]) if "min_periods" in kwargs and kwargs[ "min_periods"] is not None else length initial = int(initial) if initial and initial > 0 else 1000 offset = get_offset(offset) # Calculate Result roc_ = roc(close=close, length=length) signed_volume = signed_series(volume, initial=1) nvi = signed_volume[signed_volume < 0].abs() * roc_ nvi.fillna(0, inplace=True) nvi.iloc[0] = initial nvi = nvi.cumsum() # Offset if offset != 0: nvi = nvi.shift(offset) # Handle fills if "fillna" in kwargs: nvi.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: nvi.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it nvi.name = f"NVI_{length}" nvi.category = "volume" return nvi
def adx(high, low, close, length=None, scalar=None, drift=None, offset=None, **kwargs): """Indicator: ADX""" # Validate Arguments high = verify_series(high) low = verify_series(low) close = verify_series(close) length = length if length and length > 0 else 14 scalar = float(scalar) if scalar else 100 drift = get_drift(drift) offset = get_offset(offset) # Calculate Result atr_ = atr(high=high, low=low, close=close, length=length) up = high - high.shift(drift) # high.diff(drift) dn = low.shift(drift) - low # low.diff(-drift).shift(drift) pos = ((up > dn) & (up > 0)) * up neg = ((dn > up) & (dn > 0)) * dn pos = pos.apply(zero) neg = neg.apply(zero) k = scalar / atr_ dmp = k * rma(close=pos, length=length) dmn = k * rma(close=neg, length=length) dx = scalar * (dmp - dmn).abs() / (dmp + dmn) adx = rma(close=dx, length=length) # Offset if offset != 0: dmp = dmp.shift(offset) dmn = dmn.shift(offset) adx = adx.shift(offset) # Handle fills if "fillna" in kwargs: adx.fillna(kwargs["fillna"], inplace=True) dmp.fillna(kwargs["fillna"], inplace=True) dmn.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: adx.fillna(method=kwargs["fill_method"], inplace=True) dmp.fillna(method=kwargs["fill_method"], inplace=True) dmn.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it adx.name = f"ADX_{length}" dmp.name = f"DMP_{length}" dmn.name = f"DMN_{length}" adx.category = dmp.category = dmn.category = "trend" # Prepare DataFrame to return data = {adx.name: adx, dmp.name: dmp, dmn.name: dmn} adxdf = DataFrame(data) adxdf.name = f"ADX_{length}" adxdf.category = "trend" return adxdf
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) high_low_range = non_zero_range(high, low) length = int(length) if length and length > 0 else 20 c = float(c) if c and c > 0 else 4 mamode = mamode if isinstance(mamode, str) else "sma" drift = get_drift(drift) offset = get_offset(offset) # Calculate Result hl_ratio = high_low_range / (high + low) hl_ratio *= c _lower = low * (1 - hl_ratio) _upper = high * (1 + hl_ratio) lower = ma(mamode, _lower, length=length) mid = ma(mamode, close, length=length) upper = ma(mamode, _upper, length=length) # 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 = mid.category return accbandsdf