def mean_ad(candles: np.ndarray, period: int = 5, source_type: str = "hl2", sequential: bool = False) -> Union[float, np.ndarray]: """ Mean Absolute Deviation :param candles: np.ndarray :param period: int - default: 5 :param source_type: str - default: "hl2" :param sequential: bool - default=False :return: float | np.ndarray """ if len(candles.shape) == 1: source = candles else: candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) swv = sliding_window_view(source, window_shape=period) abs_diff = np.absolute(source - same_length(source, np.mean(swv, -1))) smv_abs_diff = sliding_window_view(abs_diff, window_shape=period) mean_abs_deviation = np.nanmean(smv_abs_diff, -1) res = same_length(source, mean_abs_deviation) return res if sequential else res[-1]
def msw(candles: np.ndarray, period: int = 5, source_type: str = "close", sequential: bool = False) -> MSW: """ MSW - Mesa Sine Wave :param candles: np.ndarray :param period: int - default: 5 :param source_type: str - default: "close" :param sequential: bool - default: False :return: MSW(sine, lead) """ candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) msw_sine, msw_lead = ti.msw(np.ascontiguousarray(source), period=period) s = same_length(candles, msw_sine) l = same_length(candles, msw_lead) if sequential: return MSW(s, l) else: return MSW(s[-1], l[-1])
def pfe(candles: np.ndarray, period: int = 10, smoothing: int = 5, source_type: str = "close", sequential: bool = False) -> Union[float, np.ndarray]: """ Polarized Fractal Efficiency (PFE) :param candles: np.ndarray :param period: int - default: 10 :param smoothing: int - default: 5 :param source_type: str - default: "close" :param sequential: bool - default=False :return: float | np.ndarray """ candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) ln = period - 1 diff = np.diff(source, ln) a = np.sqrt(np.power(diff, 2) + np.power(period, 2)) b = talib.SUM(np.sqrt(1 + np.power(np.diff(source, 1), 2)), ln) pfetmp = 100 * same_length(source, a) / same_length(source, b) res = talib.EMA(np.where(same_length(source, diff) > 0, pfetmp, -pfetmp), smoothing) return res if sequential else res[-1]
def srsi(candles: np.ndarray, period: int = 14, period_stoch: int = 14, k: int = 3, d: int = 3, source_type: str = "close", sequential: bool = False) -> StochasticRSI: """ Stochastic RSI :param candles: np.ndarray :param period_rsi: int - default: 14 - RSI Length :param period_stoch: int - default: 14 - Stochastic Length :param k: int - default: 3 :param d: int - default: 3 :param source_type: str - default: "close" :param sequential: bool - default=False :return: StochasticRSI(k, d) """ candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) rsi_np = talib.RSI(source, timeperiod=period) rsi_np = rsi_np[np.logical_not(np.isnan(rsi_np))] fast_k, fast_d = ti.stoch(rsi_np, rsi_np, rsi_np, period_stoch, k, d) if sequential: fast_k = same_length(candles, fast_k) fast_d = same_length(candles, fast_d) return StochasticRSI(fast_k, fast_d) else: return StochasticRSI(fast_k[-1], fast_d[-1])
def hwma(candles: np.ndarray, na: float = 0.2, nb: float = 0.1, nc: float = 0.1, source_type: str = "close", sequential: bool = False) -> Union[ float, np.ndarray]: """ Holt-Winter Moving Average :param candles: np.ndarray :param na: float - default: 0.2 :param nb: float - default: 0.1 :param nc: float - default: 0.1 :param source_type: str - default: "close" :param sequential: bool - default: False :return: float | np.ndarray """ if not ((0 < na < 1) or (0 < nb < 1) or (0 < nc < 1)): raise ValueError("Bad parameters. They have to be: 0 < na nb nc < 1") # Accept normal array too. if len(candles.shape) == 1: source = candles else: candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) source_without_nan = source[~np.isnan(source)] res = hwma_fast(source_without_nan, na, nb, nc) res = same_length(candles, res) return res if sequential else res[-1]
def vwma(candles: np.ndarray, period: int = 20, source_type: str = "close", sequential: bool = False) -> Union[float, np.ndarray]: """ VWMA - Volume Weighted Moving Average :param candles: np.ndarray :param period: int - default: 20 :param source_type: str - default: "close" :param sequential: bool - default=False :return: float | np.ndarray """ if len(candles.shape) == 1: source = candles else: candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) res = ti.vwma(np.ascontiguousarray(source), np.ascontiguousarray(candles[:, 5]), period=period) return same_length(candles, res) if sequential else res[-1]
def swma(candles: np.ndarray, period: int = 5, source_type: str = "close", sequential: bool = False) -> Union[float, np.ndarray]: """ Symmetric Weighted Moving Average (SWMA) :param candles: np.ndarray :param period: int - default: 5 :param source_type: str - default: "close" :param sequential: bool - default: False :return: float | np.ndarray """ # Accept normal array too. if len(candles.shape) == 1: source = candles else: candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) triangle = symmetric_triangle(period) swv = sliding_window_view(source, window_shape=period) res = np.average(swv, weights=triangle, axis=-1) return same_length(candles, res) if sequential else res[-1]
def ift_rsi(candles: np.ndarray, rsi_period: int = 5, wma_period: int = 9, source_type: str = "close", sequential: bool = False) -> Union[float, np.ndarray]: """ Modified Inverse Fisher Transform applied on RSI :param candles: np.ndarray :param rsi_period: int - default: 5 :param wma_period: int - default: 9 :param source_type: str - default: "close" :param sequential: bool - default: False :return: float | np.ndarray """ candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) v1 = 0.1 * (talib.RSI(source, rsi_period) - 50) v2 = talib.WMA(v1, wma_period) res = (((2 * v2)**2 - 1) / ((2 * v2)**2 + 1)) return same_length(candles, res) if sequential else res[-1]
def sinwma(candles: np.ndarray, period: int = 14, source_type: str = "close", sequential: bool = False) -> Union[float, np.ndarray]: """ Sine Weighted Moving Average (SINWMA) :param candles: np.ndarray :param period: int - default: 14 :param source_type: str - default: "close" :param sequential: bool - default: False :return: float | np.ndarray """ # Accept normal array too. if len(candles.shape) == 1: source = candles else: candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) sines = np.array( [np.sin((i + 1) * np.pi / (period + 1)) for i in range(period)]) w = sines / sines.sum() swv = sliding_window_view(source, window_shape=period) res = np.average(swv, weights=w, axis=-1) return same_length(candles, res) if sequential else res[-1]
def rvi(candles: np.ndarray, period: int = 10, ma_len: int = 14, matype: int = 1, source_type: str = "close", sequential: bool = False) -> Union[float, np.ndarray]: """ RVI - Relative Volatility Index :param candles: np.ndarray :param period: int - default: 10 :param ma_len: int - default: 14 :param matype: int - default: 1 :param source_type: str - default: "close" :param sequential: bool - default=False :return: float | np.ndarray """ candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) stdev = talib.STDDEV(source, timeperiod=period) diff = np.diff(source) diff = same_length(source, diff) up = np.nan_to_num(np.where(diff <= 0, 0, stdev)) down = np.nan_to_num(np.where(diff > 0, 0, stdev)) up_avg = talib.MA(up, timeperiod=ma_len, matype=matype) down_avg = talib.MA(down, timeperiod=ma_len, matype=matype) result = 100 * (up_avg / (up_avg + down_avg)) return result if sequential else result[-1]
def vidya(candles: np.ndarray, short_period: int = 2, long_period: int = 5, alpha: float = 0.2, source_type: str = "close", sequential: bool = False) -> Union[float, np.ndarray]: """ VIDYA - Variable Index Dynamic Average :param candles: np.ndarray :param short_period: int - default: 2 :param long_period: int - default: 5 :param alpha: float - default: 0.2 :param source_type: str - default: "close" :param sequential: bool - default: False :return: float | np.ndarray """ if len(candles.shape) == 1: source = candles else: candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) res = ti.vidya(np.ascontiguousarray(source), short_period=short_period, long_period=long_period, alpha=alpha) return same_length(candles, res) if sequential else res[-1]
def er(candles: np.ndarray, period: int = 5, source_type: str = "close", sequential: bool = False) -> Union[float, np.ndarray]: """ ER - The Kaufman Efficiency indicator :param candles: np.ndarray :param period: int - default: 5 :param source_type: str - default: "close" :param sequential: bool - default: False :return: float | np.ndarray """ candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) change = np.abs(np.diff(source, period)) abs_dif = np.abs(np.diff(source)) swv = sliding_window_view(abs_dif, window_shape=period) volatility = swv.sum() res = change / volatility return same_length(candles, res) if sequential else res[-1]
def fisher(candles: np.ndarray, period: int = 9, sequential: bool = False) -> FisherTransform: """ The Fisher Transform helps identify price reversals. :param candles: np.ndarray :param period: int - default: 9 :param sequential: bool - default: False :return: FisherTransform(fisher, signal) """ candles = slice_candles(candles, sequential) fisher_val, fisher_signal = ti.fisher(np.ascontiguousarray(candles[:, 3]), np.ascontiguousarray(candles[:, 4]), period=period) if sequential: return FisherTransform(same_length(candles, fisher_val), same_length(candles, fisher_signal)) else: return FisherTransform(fisher_val[-1], fisher_signal[-1])
def qstick(candles: np.ndarray, period: int = 5, sequential: bool = False) -> Union[float, np.ndarray]: """ Qstick :param candles: np.ndarray :param period: int - default: 5 :param sequential: bool - default=False :return: float | np.ndarray """ candles = slice_candles(candles, sequential) res = ti.qstick(np.ascontiguousarray(candles[:, 1]), np.ascontiguousarray(candles[:, 2]), period=period) return same_length(candles, res) if sequential else res[-1]
def mass(candles: np.ndarray, period: int = 5, sequential: bool = False) -> Union[float, np.ndarray]: """ MASS - Mass Index :param candles: np.ndarray :param period: int - default: 5 :param sequential: bool - default: False :return: float | np.ndarray """ candles = slice_candles(candles, sequential) res = ti.mass(np.ascontiguousarray(candles[:, 3]), np.ascontiguousarray(candles[:, 4]), period=period) return same_length(candles, res) if sequential else res[-1]
def marketfi(candles: np.ndarray, sequential: bool = False) -> Union[float, np.ndarray]: """ MARKETFI - Market Facilitation Index :param candles: np.ndarray :param sequential: bool - default: False :return: float | np.ndarray """ candles = slice_candles(candles, sequential) res = ti.marketfi(np.ascontiguousarray(candles[:, 3]), np.ascontiguousarray(candles[:, 4]), np.ascontiguousarray(candles[:, 5])) return same_length(candles, res) if sequential else res[-1]
def wad(candles: np.ndarray, sequential: bool = False) -> Union[float, np.ndarray]: """ WAD - Williams Accumulation/Distribution :param candles: np.ndarray :param sequential: bool - default=False :return: float | np.ndarray """ candles = slice_candles(candles, sequential) res = ti.wad(np.ascontiguousarray(candles[:, 3]), np.ascontiguousarray(candles[:, 4]), np.ascontiguousarray(candles[:, 1])) return same_length(candles, res) if sequential else res[-1]
def cvi(candles: np.ndarray, period: int = 5, sequential: bool = False) -> Union[float, np.ndarray]: """ CVI - Chaikins Volatility :param candles: np.ndarray :param period: int - default: 5 :param sequential: bool - default=False :return: float | np.ndarray """ candles = slice_candles(candles, sequential) res = ti.cvi(np.ascontiguousarray(candles[:, 3]), np.ascontiguousarray(candles[:, 4]), period=period) return same_length(candles, res) if sequential else res[-1]
def nvi(candles: np.ndarray, source_type: str = "close", sequential: bool = False) -> Union[float, np.ndarray]: """ NVI - Negative Volume Index :param candles: np.ndarray :param source_type: str - default: "close" :param sequential: bool - default: False :return: float | np.ndarray """ candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) res = ti.nvi(np.ascontiguousarray(source), np.ascontiguousarray(candles[:, 5])) return same_length(candles, res) if sequential else res[-1]
def emv(candles: np.ndarray, sequential: bool = False) -> Union[float, np.ndarray]: """ EMV - Ease of Movement :param candles: np.ndarray :param sequential: bool - default: False :return: float | np.ndarray """ candles = slice_candles(candles, sequential) res = ti.emv(np.ascontiguousarray(candles[:, 3]), np.ascontiguousarray(candles[:, 4]), np.ascontiguousarray(candles[:, 5])) return same_length(candles, res) if sequential else res[-1]
def vosc(candles: np.ndarray, short_period: int = 2, long_period: int = 5, sequential: bool = False) -> Union[ float, np.ndarray]: """ VOSC - Volume Oscillator :param candles: np.ndarray :param short_period: int - default: 2 :param long_period: int - default: 5 :param sequential: bool - default=False :return: float | np.ndarray """ candles = slice_candles(candles, sequential) res = ti.vosc(np.ascontiguousarray(candles[:, 5]), short_period=short_period, long_period=long_period) return same_length(candles, res) if sequential else res[-1]
def cg(candles: np.ndarray, period: int = 10, source_type: str = "close", sequential: bool = False) -> Union[ float, np.ndarray]: """ Center of Gravity (CG) :param candles: np.ndarray :param period: int - default: 10 :param source_type: str - default: "close" :param sequential: bool - default=False :return: float | np.ndarray """ candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) res = go_fast(source, period) return same_length(candles, res) if sequential else res[-1]
def dpo(candles: np.ndarray, period: int = 5, source_type: str = "close", sequential: bool = False) -> Union[ float, np.ndarray]: """ DPO - Detrended Price Oscillator :param candles: np.ndarray :param period: int - default: 5 :param source_type: str - default: "close" :param sequential: bool - default=False :return: float | np.ndarray """ candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) res = ti.dpo(np.ascontiguousarray(source), period=period) return same_length(candles, res) if sequential else res[-1]
def macdext(candles: np.ndarray, fast_period: int = 12, fast_matype: int = 0, slow_period: int = 26, slow_matype: int = 0, signal_period: int = 9, signal_matype: int = 0, source_type: str = "close", sequential: bool = False) -> MACDEXT: """ MACDEXT - MACD with controllable MA type :param candles: np.ndarray :param fast_period: int - default: 12 :param fast_matype: int - default: 0 :param slow_period: int - default: 26 :param slow_matype: int - default: 0 :param signal_period: int - default: 9 :param signal_matype: int - default: 0 :param source_type: str - default: "close" :param sequential: bool - default: False :return: MACDEXT(macd, signal, hist) """ candles = slice_candles(candles, sequential) if fast_matype == 29 or slow_matype == 29 or signal_matype == 29: raise ValueError("VWAP not supported in macdext.") ma_fast = ma(candles, period=fast_period, matype=fast_matype, source_type=source_type, sequential=True) ma_slow = ma(candles, period=slow_period, matype=slow_matype, source_type=source_type, sequential=True) macd = ma_fast - ma_slow if signal_matype == 24: # volume needed. candles[:, 2] = macd candles_without_nan = candles[~np.isnan(candles).any(axis=1)] macdsignal = ma(candles_without_nan, period=signal_period, matype=signal_matype, source_type="close", sequential=True) else: macd_without_nan = macd[~np.isnan(macd)] macdsignal = ma(macd_without_nan, period=signal_period, matype=signal_matype, sequential=True) macdsignal = same_length(candles, macdsignal) macdhist = macd - macdsignal if sequential: return MACDEXT(macd, macdsignal, macdhist) else: return MACDEXT(macd[-1], macdsignal[-1], macdhist[-1])
def maaq(candles: np.ndarray, period: int = 11, fast_period: int = 2, slow_period: int = 30, source_type: str = "close", sequential: bool = False) -> Union[float, np.ndarray]: """ Moving Average Adaptive Q :param candles: np.ndarray :param period: int - default: 11 :param fast_period: int - default: 2 :param slow_period: int - default: 30 :param source_type: str - default: "close" :param sequential: bool - default: False :return: float | np.ndarray """ # Accept normal array too. if len(candles.shape) == 1: source = candles else: candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) source = source[~np.isnan(source)] diff = np.abs(source - np_shift(source, 1, np.nan)) signal = np.abs(source - np_shift(source, period, np.nan)) noise = talib.SUM(diff, period) with np.errstate(divide='ignore'): ratio = np.where(noise == 0, 0, signal / noise) fastSc = 2 / (fast_period + 1) slowSc = 2 / (slow_period + 1) temp = np.power((ratio * fastSc) + slowSc, 2) res = maaq_fast(source, temp, period) res = same_length(candles, res) return res if sequential else res[-1]
def wilders(candles: np.ndarray, period: int = 5, source_type: str = "close", sequential: bool = False) -> Union[float, np.ndarray]: """ WILDERS - Wilders Smoothing :param candles: np.ndarray :param period: int - default: 5 :param source_type: str - default: "close" :param sequential: bool - default=False :return: float | np.ndarray """ candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) res = ti.wilders(np.ascontiguousarray(source), period=period) return same_length(candles, res) if sequential else res[-1]
def kurtosis(candles: np.ndarray, period: int = 5, source_type: str = "hl2", sequential: bool = False) -> Union[ float, np.ndarray]: """ Skewness :param candles: np.ndarray :param period: int - default: 5 :param source_type: str - default: "hl2" :param sequential: bool - default: False :return: float | np.ndarray """ candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) swv = sliding_window_view(source, window_shape=period) kurtosis = stats.kurtosis(swv, axis=-1) res = same_length(source, kurtosis) return res if sequential else res[-1]
def zlema(candles: np.ndarray, period: int = 20, source_type: str = "close", sequential: bool = False) -> Union[float, np.ndarray]: """ Zero-Lag Exponential Moving Average :param candles: np.ndarray :param period: int - default: 20 :param source_type: str - default: "close" :param sequential: bool - default=False :return: float | np.ndarray """ candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) res = ti.zlema(np.ascontiguousarray(source), period=period) return same_length(candles, res) if sequential else res[-1]
def ttm_trend(candles: np.ndarray, period: int = 5, source_type: str = "hl2", sequential: bool = False) -> Union[float, np.ndarray]: """ TTM Trend :param candles: np.ndarray :param period: int - default: 5 :param source_type: str - default: "hl2" :param sequential: bool - default=False :return: float | np.ndarray """ candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) swv = sliding_window_view(source, window_shape=period) trend_avg = np.mean(swv, axis=-1) res = np.greater(candles[:, 2], same_length(source, trend_avg)) return res if sequential else res[-1]
def hma(candles: np.ndarray, period: int = 5, source_type: str = "close", sequential: bool = False) -> Union[ float, np.ndarray]: """ Hull Moving Average :param candles: np.ndarray :param period: int - default: 5 :param source_type: str - default: "close" :param sequential: bool - default=False :return: float | np.ndarray """ # Accept normal array too. if len(candles.shape) == 1: source = candles else: candles = slice_candles(candles, sequential) source = get_candle_source(candles, source_type=source_type) res = ti.hma(np.ascontiguousarray(source), period=period) return same_length(candles, res) if sequential else res[-1]