# -*- coding: utf-8 -*- from pathlib import Path from sys import float_info as sflt from numpy import argmax, argmin from pandas import DataFrame, Series from pandas.api.types import is_datetime64_any_dtype def category_files(category: str) -> list: """Helper function to return all filenames in the category directory.""" files = [ x.stem for x in list(Path(f"pandas_ta/{category}/").glob("*.py")) if x.stem != "__init__" ] return files def get_drift(x: int) -> int: """Returns an int if not zero, otherwise defaults to one.""" return int(x) if isinstance(x, int) and x != 0 else 1 def get_offset(x: int) -> int: """Returns an int, otherwise defaults to zero.""" return int(x) if isinstance(x, int) else 0 def is_datetime_ordered(df: DataFrame or Series) -> bool: """Returns True if the index is a datetime and ordered.""" index_is_datetime = is_datetime64_any_dtype(df.index) try: ordered = df.index[0] < df.index[-1] except RuntimeWarning: pass finally: return True if index_is_datetime and ordered else False def is_percent(x: int or float) -> bool: if isinstance(x, (int, float)): return x is not None and x >= 0 and x <= 100 return False def non_zero_range(high: Series, low: Series) -> Series: """Returns the difference of two series and adds epsilon to any zero values. This occurs commonly in crypto data when 'high' = 'low'.""" diff = high - low if diff.eq(0).any().any(): diff += sflt.epsilon return diff def recent_maximum_index(x): return int(argmax(x[::-1])) def recent_minimum_index(x): return int(argmin(x[::-1])) def signed_series(series: Series, initial: int = None) -> Series: """Returns a Signed Series with or without an initial value Default Example: series = Series([3, 2, 2, 1, 1, 5, 6, 6, 7, 5]) and returns: sign = Series([NaN, -1.0, 0.0, -1.0, 0.0, 1.0, 1.0, 0.0, 1.0, -1.0]) """ series = verify_series(series) sign = series.diff(1) sign[sign > 0] = 1 sign[sign < 0] = -1 sign.iloc[0] = initial return sign def unsigned_differences(series: Series, amount: int = None, **kwargs) -> Series: """Unsigned Differences Returns two Series, an unsigned positive and unsigned negative series based on the differences of the original series. The positive series are only the increases and the negative series is only the decreases. Default Example: series = Series([3, 2, 2, 1, 1, 5, 6, 6, 7, 5, 3]) and returns postive = Series([0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0]) negative = Series([0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1]) """ amount = int(amount) if amount is not None else 1 negative = series.diff(amount) negative.fillna(0, inplace=True) positive = negative.copy() positive[positive <= 0] = 0 positive[positive > 0] = 1 negative[negative >= 0] = 0 negative[negative < 0] = 1 if kwargs.pop("asint", False): positive = positive.astype(int) negative = negative.astype(int) return positive, negative def verify_series(series: Series) -> Series: """If a Pandas Series return it.""" if series is not None and isinstance(series, Series): return series