def amat(close=None, fast=None, slow=None, mamode=None, lookback=None, offset=None, **kwargs): """Indicator: Archer Moving Averages Trends (AMAT)""" # Validate Arguments close = verify_series(close) fast = int(fast) if fast and fast > 0 else 8 slow = int(slow) if slow and slow > 0 else 21 lookback = int(lookback) if lookback and lookback > 0 else 2 mamode = mamode.lower() if mamode else "ema" offset = get_offset(offset) # Calculate Result if mamode == "hma": fast_ma = hma(close=close, length=fast, **kwargs) slow_ma = hma(close=close, length=slow, **kwargs) elif mamode == "linreg": fast_ma = linreg(close=close, length=fast, **kwargs) slow_ma = linreg(close=close, length=slow, **kwargs) elif mamode == "rma": fast_ma = rma(close=close, length=fast, **kwargs) slow_ma = rma(close=close, length=slow, **kwargs) elif mamode == "sma": fast_ma = sma(close=close, length=fast, **kwargs) slow_ma = sma(close=close, length=slow, **kwargs) elif mamode == "wma": fast_ma = wma(close=close, length=fast, **kwargs) slow_ma = wma(close=close, length=slow, **kwargs) else: # "ema" fast_ma = ema(close=close, length=fast, **kwargs) slow_ma = ema(close=close, length=slow, **kwargs) mas_long = long_run(fast_ma, slow_ma, length=lookback) mas_short = short_run(fast_ma, slow_ma, length=lookback) # Offset if offset != 0: mas_long = mas_long.shift(offset) mas_short = mas_short.shift(offset) # # Handle fills if "fillna" in kwargs: mas_long.fillna(kwargs["fillna"], inplace=True) mas_short.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: mas_long.fillna(method=kwargs["fill_method"], inplace=True) mas_short.fillna(method=kwargs["fill_method"], inplace=True) # Prepare DataFrame to return amatdf = DataFrame({ f"AMAT_{mas_long.name}": mas_long, f"AMAT_{mas_short.name}": mas_short }) # Name and Categorize it amatdf.name = f"AMAT_{mamode.upper()}_{fast}_{slow}_{lookback}" amatdf.category = "trend" return amatdf
def qstick(open_, close, length=None, offset=None, **kwargs): """Indicator: Q Stick""" # Validate Arguments length = int(length) if length and length > 0 else 10 ma = kwargs.pop("ma", "sma") open_ = verify_series(open_, length) close = verify_series(close, length) offset = get_offset(offset) if open_ is None or close is None: return # Calculate Result diff = non_zero_range(close, open_) if ma == "dema": qstick = dema(diff, length=length, **kwargs) elif ma == "ema": qstick = ema(diff, length=length, **kwargs) elif ma == "hma": qstick = hma(diff, length=length) elif ma == "rma": qstick = rma(diff, length=length) else: # "sma" qstick = sma(diff, length=length) # Offset if offset != 0: qstick = qstick.shift(offset) # Handle fills if "fillna" in kwargs: qstick.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: qstick.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it qstick.name = f"QS_{length}" qstick.category = "trend" return qstick
def bias(close, length=None, mamode=None, offset=None, **kwargs): """Indicator: Bias (BIAS)""" # Validate Arguments close = verify_series(close) length = int(length) if length and length > 0 else 26 mamode = mamode.lower() if mamode else None offset = get_offset(offset) # Calculate Result if mamode == "ema": ma = ema(close, length=length, **kwargs) elif mamode == "hma": ma = hma(close, length=length, **kwargs) elif mamode == "rma": ma = rma(close, length=length, **kwargs) elif mamode == "wma": ma = wma(close, length=length, **kwargs) else: # "sma" ma = sma(close, length=length, **kwargs) bias = (close / ma) - 1 # Offset if offset != 0: bias = bias.shift(offset) # Handle fills if "fillna" in kwargs: bias.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: bias.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it bias.name = f"BIAS_{ma.name}" bias.category = "momentum" return bias
def aobv(close, volume, fast=None, slow=None, mamode=None, max_lookback=None, min_lookback=None, offset=None, **kwargs): """Indicator: Archer On Balance Volume (AOBV)""" # Validate arguments close = verify_series(close) volume = verify_series(volume) offset = get_offset(offset) fast = int(fast) if fast and fast > 0 else 4 slow = int(slow) if slow and slow > 0 else 12 max_lookback = int( max_lookback) if max_lookback and max_lookback > 0 else 2 min_lookback = int( min_lookback) if min_lookback and min_lookback > 0 else 2 if slow < fast: fast, slow = slow, fast mamode = mamode.upper() if mamode else None run_length = kwargs.pop("run_length", 2) # Calculate Result obv_ = obv(close=close, volume=volume, **kwargs) if mamode is None or mamode == "EMA": mamode = "EMA" maf = ema(close=obv_, length=fast, **kwargs) mas = ema(close=obv_, length=slow, **kwargs) elif mamode == "HMA": maf = hma(close=obv_, length=fast, **kwargs) mas = hma(close=obv_, length=slow, **kwargs) elif mamode == "LINREG": maf = linreg(close=obv_, length=fast, **kwargs) mas = linreg(close=obv_, length=slow, **kwargs) elif mamode == "SMA": maf = sma(close=obv_, length=fast, **kwargs) mas = sma(close=obv_, length=slow, **kwargs) elif mamode == "WMA": maf = wma(close=obv_, length=fast, **kwargs) mas = wma(close=obv_, length=slow, **kwargs) # When MAs are long and short obv_long = long_run(maf, mas, length=run_length) obv_short = short_run(maf, mas, length=run_length) # Offset if offset != 0: obv_ = obv_.shift(offset) maf = maf.shift(offset) mas = mas.shift(offset) obv_long = obv_long.shift(offset) obv_short = obv_short.shift(offset) # # Handle fills if "fillna" in kwargs: obv_.fillna(kwargs["fillna"], inplace=True) maf.fillna(kwargs["fillna"], inplace=True) mas.fillna(kwargs["fillna"], inplace=True) obv_long.fillna(kwargs["fillna"], inplace=True) obv_short.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: obv_.fillna(method=kwargs["fill_method"], inplace=True) maf.fillna(method=kwargs["fill_method"], inplace=True) mas.fillna(method=kwargs["fill_method"], inplace=True) obv_long.fillna(method=kwargs["fill_method"], inplace=True) obv_short.fillna(method=kwargs["fill_method"], inplace=True) # Prepare DataFrame to return data = { obv_.name: obv_, f"OBV_min_{min_lookback}": obv_.rolling(min_lookback).min(), f"OBV_max_{max_lookback}": obv_.rolling(max_lookback).max(), f"OBV_{maf.name}": maf, f"OBV_{mas.name}": mas, f"AOBV_LR_{run_length}": obv_long, f"AOBV_SR_{run_length}": obv_short, } aobvdf = DataFrame(data) # Name and Categorize it aobvdf.name = ( f"AOBV_{mamode}_{fast}_{slow}_{min_lookback}_{max_lookback}_{run_length}" ) aobvdf.category = "volume" return aobvdf
def qqe(close, length=None, smooth=None, factor=None, mamode=None, drift=None, offset=None, **kwargs): """Indicator: Quantitative Qualitative Estimation (QQE)""" # Validate arguments close = verify_series(close) length = int(length) if length and length > 0 else 14 smooth = int(smooth) if smooth and smooth > 0 else 5 factor = float(factor) if factor else 4.236 mamode = mamode.lower() if mamode else "ema" drift = get_drift(drift) offset = get_offset(offset) # Calculate Result rsi_ = rsi(close, length) if mamode == "hma": rsi_ma, _mode = hma(rsi_, length=smooth), "h" elif mamode == "rma": rsi_ma, _mode = rma(rsi_, length=smooth), "r" elif mamode == "sma": rsi_ma, _mode = sma(rsi_, length=smooth), "s" elif mamode == "wma": rsi_ma, _mode = wma(rsi_, length=smooth), "w" else: # "ema" rsi_ma, _mode = ema(rsi_, length=smooth), "" # RSI MA True Range rsi_ma_tr = rsi_ma.diff(drift).abs() # Double Smooth the RSI MA True Range using Wilder's Length with a default # width of 4.236. wilders_length = 2 * length - 1 smoothed_rsi_tr_ma = ema(rsi_ma_tr, length=wilders_length) dar = factor * ema(smoothed_rsi_tr_ma, length=wilders_length) # Create the Upper and Lower Bands around RSI MA. upperband = rsi_ma + dar lowerband = rsi_ma - dar m = close.size long = Series(0, index=close.index) short = Series(0, index=close.index) trend = Series(1, index=close.index) qqe = Series(rsi_ma.iloc[0], index=close.index) qqe_long = Series(npNaN, index=close.index) qqe_short = Series(npNaN, index=close.index) for i in range(1, m): c_rsi, p_rsi = rsi_ma.iloc[i], rsi_ma.iloc[i - 1] c_long, p_long = long.iloc[i - 1], long.iloc[i - 2] c_short, p_short = short.iloc[i - 1], short.iloc[i - 2] # Long Line if p_rsi > c_long and c_rsi > c_long: long.iloc[i] = npMaximum(c_long, lowerband.iloc[i]) else: long.iloc[i] = lowerband.iloc[i] # Short Line if p_rsi < c_short and c_rsi < c_short: short.iloc[i] = npMinimum(c_short, upperband.iloc[i]) else: short.iloc[i] = upperband.iloc[i] # Trend & QQE Calculation # Long: Current RSI_MA value Crosses the Prior Short Line Value # Short: Current RSI_MA Crosses the Prior Long Line Value if (c_rsi > c_short and p_rsi < p_short) or (c_rsi <= c_short and p_rsi >= p_short): trend.iloc[i] = 1 qqe.iloc[i] = qqe_long.iloc[i] = long.iloc[i] elif (c_rsi > c_long and p_rsi < p_long) or (c_rsi <= c_long and p_rsi >= p_long): trend.iloc[i] = -1 qqe.iloc[i] = qqe_short.iloc[i] = short.iloc[i] else: trend.iloc[i] = trend.iloc[i - 1] if trend.iloc[i] == 1: qqe.iloc[i] = qqe_long.iloc[i] = long.iloc[i] else: qqe.iloc[i] = qqe_short.iloc[i] = short.iloc[i] # Offset if offset != 0: rsi_ma = rsi_ma.shift(offset) qqe = qqe.shift(offset) long = long.shift(offset) short = short.shift(offset) # Handle fills if "fillna" in kwargs: rsi_ma.fillna(kwargs["fillna"], inplace=True) qqe.fillna(kwargs["fillna"], inplace=True) long.fillna(kwargs["fillna"], inplace=True) short.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: rsi_ma.fillna(method=kwargs["fill_method"], inplace=True) qqe.fillna(method=kwargs["fill_method"], inplace=True) long.fillna(method=kwargs["fill_method"], inplace=True) short.fillna(method=kwargs["fill_method"], inplace=True) # Name and Categorize it _props = f"{_mode}_{length}_{smooth}_{factor}" qqe.name = f"QQE{_props}" rsi_ma.name = f"QQE{_props}_RSI{_mode.upper()}MA" long.name = f"QQEl{_props}" short.name = f"QQEs{_props}" qqe.category = rsi_ma.category = "momentum" long.category = short.category = qqe.category # Prepare DataFrame to return data = { qqe.name: qqe, rsi_ma.name: rsi_ma, # long.name: long, short.name: short long.name: qqe_long, short.name: qqe_short } df = DataFrame(data) df.name = f"QQE{_props}" df.category = qqe.category return df