Files
2026-07-09 05:08:16 +08:00

2823 lines
59 KiB
Python

"""
Cross-library wrapper registry — comprehensive indicator coverage.
Unified interface: execute_indicator(library, indicator, data, df=None, **kwargs)
Supported libraries: ferro_ta, talib, pandas_ta, ta, tulipy, finta
50+ indicators across all categories.
"""
from __future__ import annotations
from typing import Any
import numpy as np
def _try_import(name):
try:
import importlib
return importlib.import_module(name)
except ImportError:
return None
_talib = _try_import("talib")
_pta = _try_import("pandas_ta")
_ta = _try_import("ta")
_tl = _try_import("tulipy")
_fi_m = _try_import("finta")
_fi = getattr(_fi_m, "TA", None) if _fi_m else None
def available_libraries():
libs = ["ferro_ta"]
if _talib:
libs.append("talib")
if _pta:
libs.append("pandas_ta")
if _ta:
libs.append("ta")
if _tl:
libs.append("tulipy")
if _fi:
libs.append("finta")
return libs
def is_supported(library: str, indicator: str) -> bool:
"""Return True if a wrapper exists for the given (library, indicator) pair."""
if library not in available_libraries():
return False
return (library, indicator) in REGISTRY
def _strip_nan(arr):
a = np.asarray(arr, dtype=np.float64).ravel()
return a[np.isfinite(a)]
def _c64(a):
return np.ascontiguousarray(a, dtype=np.float64)
def _empty():
return np.array([], dtype=np.float64)
def _first_col(df, prefix):
col = next((c for c in df.columns if c.startswith(prefix)), None)
return _strip_nan(df[col].values) if col is not None else _empty()
# ============================================================
# OVERLAP
# ============================================================
def _sma_ft(d, df, timeperiod=20, **_):
import ferro_ta
return _strip_nan(ferro_ta.SMA(d["close"], timeperiod=timeperiod))
def _sma_tl(d, df, timeperiod=20, **_):
return _strip_nan(_talib.SMA(d["close"], timeperiod=timeperiod))
def _sma_pt(d, df, timeperiod=20, **_):
return _strip_nan(_pta.sma(df["close"], length=timeperiod).values)
def _sma_ta(d, df, timeperiod=20, **_):
from ta.trend import SMAIndicator
return _strip_nan(
SMAIndicator(df["close"], window=timeperiod).sma_indicator().values
)
def _sma_tu(d, df, timeperiod=20, **_):
return _strip_nan(_tl.sma(_c64(d["close"]), period=timeperiod))
def _sma_fi(d, df, timeperiod=20, **_):
return _strip_nan(_fi.SMA(df, timeperiod).values)
def _ema_ft(d, df, timeperiod=20, **_):
import ferro_ta
return _strip_nan(ferro_ta.EMA(d["close"], timeperiod=timeperiod))
def _ema_tl(d, df, timeperiod=20, **_):
return _strip_nan(_talib.EMA(d["close"], timeperiod=timeperiod))
def _ema_pt(d, df, timeperiod=20, **_):
return _strip_nan(_pta.ema(df["close"], length=timeperiod).values)
def _ema_ta(d, df, timeperiod=20, **_):
from ta.trend import EMAIndicator
return _strip_nan(
EMAIndicator(df["close"], window=timeperiod).ema_indicator().values
)
def _ema_tu(d, df, timeperiod=20, **_):
return _strip_nan(_tl.ema(_c64(d["close"]), period=timeperiod))
def _ema_fi(d, df, timeperiod=20, **_):
return _strip_nan(_fi.EMA(df, timeperiod).values)
def _wma_ft(d, df, timeperiod=14, **_):
import ferro_ta
return _strip_nan(ferro_ta.WMA(d["close"], timeperiod=timeperiod))
def _wma_tl(d, df, timeperiod=14, **_):
return _strip_nan(_talib.WMA(d["close"], timeperiod=timeperiod))
def _wma_pt(d, df, timeperiod=14, **_):
return _strip_nan(_pta.wma(df["close"], length=timeperiod).values)
def _wma_ta(d, df, **_):
return _empty()
_wma_ta._stub = True
def _wma_tu(d, df, timeperiod=14, **_):
return _strip_nan(_tl.wma(_c64(d["close"]), period=timeperiod))
def _wma_fi(d, df, timeperiod=14, **_):
return _strip_nan(_fi.WMA(df, timeperiod).values)
def _dema_ft(d, df, timeperiod=20, **_):
import ferro_ta
return _strip_nan(ferro_ta.DEMA(d["close"], timeperiod=timeperiod))
def _dema_tl(d, df, timeperiod=20, **_):
return _strip_nan(_talib.DEMA(d["close"], timeperiod=timeperiod))
def _dema_pt(d, df, timeperiod=20, **_):
return _strip_nan(_pta.dema(df["close"], length=timeperiod).values)
def _dema_ta(d, df, **_):
return _empty()
_dema_ta._stub = True
def _dema_tu(d, df, timeperiod=20, **_):
return _strip_nan(_tl.dema(_c64(d["close"]), period=timeperiod))
def _dema_fi(d, df, timeperiod=20, **_):
return _strip_nan(_fi.DEMA(df, timeperiod).values)
def _tema_ft(d, df, timeperiod=20, **_):
import ferro_ta
return _strip_nan(ferro_ta.TEMA(d["close"], timeperiod=timeperiod))
def _tema_tl(d, df, timeperiod=20, **_):
return _strip_nan(_talib.TEMA(d["close"], timeperiod=timeperiod))
def _tema_pt(d, df, timeperiod=20, **_):
return _strip_nan(_pta.tema(df["close"], length=timeperiod).values)
def _tema_ta(d, df, **_):
return _empty()
_tema_ta._stub = True
def _tema_tu(d, df, timeperiod=20, **_):
return _strip_nan(_tl.tema(_c64(d["close"]), period=timeperiod))
def _tema_fi(d, df, timeperiod=20, **_):
return _strip_nan(_fi.TEMA(df, timeperiod).values)
def _t3_ft(d, df, timeperiod=5, **_):
import ferro_ta
return _strip_nan(ferro_ta.T3(d["close"], timeperiod=timeperiod))
def _t3_tl(d, df, timeperiod=5, **_):
return _strip_nan(_talib.T3(d["close"], timeperiod=timeperiod))
def _t3_pt(d, df, timeperiod=5, **_):
return _strip_nan(_pta.t3(df["close"], length=timeperiod).values)
def _t3_ta(d, df, **_):
return _empty()
_t3_ta._stub = True
def _t3_tu(d, df, **_):
return _empty()
_t3_tu._stub = True
def _t3_fi(d, df, **_):
return _empty()
_t3_fi._stub = True
def _trima_ft(d, df, timeperiod=20, **_):
import ferro_ta
return _strip_nan(ferro_ta.TRIMA(d["close"], timeperiod=timeperiod))
def _trima_tl(d, df, timeperiod=20, **_):
return _strip_nan(_talib.TRIMA(d["close"], timeperiod=timeperiod))
def _trima_pt(d, df, timeperiod=20, **_):
return _strip_nan(_pta.trima(df["close"], length=timeperiod).values)
def _trima_ta(d, df, **_):
return _empty()
_trima_ta._stub = True
def _trima_tu(d, df, timeperiod=20, **_):
return _strip_nan(_tl.trima(_c64(d["close"]), period=timeperiod))
def _trima_fi(d, df, timeperiod=20, **_):
return _strip_nan(_fi.TRIMA(df, timeperiod).values)
def _kama_ft(d, df, timeperiod=10, **_):
import ferro_ta
return _strip_nan(ferro_ta.KAMA(d["close"], timeperiod=timeperiod))
def _kama_tl(d, df, timeperiod=10, **_):
return _strip_nan(_talib.KAMA(d["close"], timeperiod=timeperiod))
def _kama_pt(d, df, timeperiod=10, **_):
return _strip_nan(_pta.kama(df["close"], length=timeperiod).values)
def _kama_ta(d, df, **_):
return _empty()
_kama_ta._stub = True
def _kama_tu(d, df, timeperiod=10, **_):
return _strip_nan(_tl.kama(_c64(d["close"]), period=timeperiod))
def _kama_fi(d, df, **_):
return _empty()
_kama_fi._stub = True
def _hma_ft(d, df, timeperiod=16, **_):
import ferro_ta
return _strip_nan(ferro_ta.HULL_MA(d["close"], timeperiod=timeperiod))
def _hma_tl(d, df, **_):
return _empty()
_hma_tl._stub = True
def _hma_pt(d, df, timeperiod=16, **_):
return _strip_nan(_pta.hma(df["close"], length=timeperiod).values)
def _hma_ta(d, df, **_):
return _empty()
_hma_ta._stub = True
def _hma_tu(d, df, timeperiod=16, **_):
return _strip_nan(_tl.hma(_c64(d["close"]), period=timeperiod))
def _hma_fi(d, df, timeperiod=16, **_):
return _strip_nan(_fi.HMA(df, timeperiod).values)
def _vwma_ft(d, df, timeperiod=20, **_):
import ferro_ta
return _strip_nan(ferro_ta.VWMA(d["close"], d["volume"], timeperiod=timeperiod))
def _vwma_tl(d, df, **_):
return _empty()
_vwma_tl._stub = True
def _vwma_pt(d, df, timeperiod=20, **_):
r = _pta.vwma(df["close"], df["volume"], length=timeperiod)
return _strip_nan(r.values) if r is not None else _empty()
def _vwma_ta(d, df, **_):
return _empty()
_vwma_ta._stub = True
def _vwma_tu(d, df, timeperiod=20, **_):
return _strip_nan(_tl.vwma(_c64(d["close"]), _c64(d["volume"]), period=timeperiod))
def _vwma_fi(d, df, **_):
return _empty()
_vwma_fi._stub = True
def _midpoint_ft(d, df, timeperiod=14, **_):
import ferro_ta
return _strip_nan(ferro_ta.MIDPOINT(d["close"], timeperiod=timeperiod))
def _midpoint_tl(d, df, timeperiod=14, **_):
return _strip_nan(_talib.MIDPOINT(d["close"], timeperiod=timeperiod))
def _midpoint_pt(d, df, **_):
return _empty()
_midpoint_pt._stub = True
def _midpoint_ta(d, df, **_):
return _empty()
_midpoint_ta._stub = True
def _midpoint_tu(d, df, **_):
return _empty()
_midpoint_tu._stub = True
def _midpoint_fi(d, df, **_):
return _empty()
_midpoint_fi._stub = True
def _midprice_ft(d, df, timeperiod=14, **_):
import ferro_ta
return _strip_nan(ferro_ta.MIDPRICE(d["high"], d["low"], timeperiod=timeperiod))
def _midprice_tl(d, df, timeperiod=14, **_):
return _strip_nan(_talib.MIDPRICE(d["high"], d["low"], timeperiod=timeperiod))
def _midprice_pt(d, df, **_):
return _empty()
_midprice_pt._stub = True
def _midprice_ta(d, df, **_):
return _empty()
_midprice_ta._stub = True
def _midprice_tu(d, df, **_):
return _empty()
_midprice_tu._stub = True
def _midprice_fi(d, df, **_):
return _empty()
_midprice_fi._stub = True
# ============================================================
# MOMENTUM
# ============================================================
def _rsi_ft(d, df, timeperiod=14, **_):
import ferro_ta
return _strip_nan(ferro_ta.RSI(d["close"], timeperiod=timeperiod))
def _rsi_tl(d, df, timeperiod=14, **_):
return _strip_nan(_talib.RSI(d["close"], timeperiod=timeperiod))
def _rsi_pt(d, df, timeperiod=14, **_):
return _strip_nan(_pta.rsi(df["close"], length=timeperiod).values)
def _rsi_ta(d, df, timeperiod=14, **_):
from ta.momentum import RSIIndicator
return _strip_nan(RSIIndicator(df["close"], window=timeperiod).rsi().values)
def _rsi_tu(d, df, timeperiod=14, **_):
return _strip_nan(_tl.rsi(_c64(d["close"]), period=timeperiod))
def _rsi_fi(d, df, timeperiod=14, **_):
return _strip_nan(_fi.RSI(df, timeperiod).values)
def _macd_ft(d, df, fastperiod=12, slowperiod=26, signalperiod=9, **_):
import ferro_ta
m, s, h = ferro_ta.MACD(
d["close"],
fastperiod=fastperiod,
slowperiod=slowperiod,
signalperiod=signalperiod,
)
return _strip_nan(m)
def _macd_tl(d, df, fastperiod=12, slowperiod=26, signalperiod=9, **_):
m, s, h = _talib.MACD(
d["close"],
fastperiod=fastperiod,
slowperiod=slowperiod,
signalperiod=signalperiod,
)
return _strip_nan(m)
def _macd_pt(d, df, fastperiod=12, slowperiod=26, signalperiod=9, **_):
r = _pta.macd(df["close"], fast=fastperiod, slow=slowperiod, signal=signalperiod)
return _first_col(r, "MACD_")
def _macd_ta(d, df, fastperiod=12, slowperiod=26, signalperiod=9, **_):
from ta.trend import MACD
return _strip_nan(
MACD(
df["close"],
window_fast=fastperiod,
window_slow=slowperiod,
window_sign=signalperiod,
)
.macd()
.values
)
def _macd_tu(d, df, fastperiod=12, slowperiod=26, signalperiod=9, **_):
m, s, h = _tl.macd(
_c64(d["close"]),
short_period=fastperiod,
long_period=slowperiod,
signal_period=signalperiod,
)
return _strip_nan(m)
def _macd_fi(d, df, fastperiod=12, slowperiod=26, signalperiod=9, **_):
return _strip_nan(_fi.MACD(df, fastperiod, slowperiod, signalperiod)["MACD"].values)
def _stoch_ft(d, df, fastk_period=14, slowk_period=3, slowd_period=3, **_):
import ferro_ta
k, dd = ferro_ta.STOCH(
d["high"],
d["low"],
d["close"],
fastk_period=fastk_period,
slowk_period=slowk_period,
slowd_period=slowd_period,
)
return _strip_nan(k)
def _stoch_tl(d, df, fastk_period=14, slowk_period=3, slowd_period=3, **_):
k, dd = _talib.STOCH(
d["high"],
d["low"],
d["close"],
fastk_period=fastk_period,
slowk_period=slowk_period,
slowd_period=slowd_period,
)
return _strip_nan(k)
def _stoch_pt(d, df, fastk_period=14, slowk_period=3, slowd_period=3, **_):
r = _pta.stoch(df["high"], df["low"], df["close"], k=fastk_period, d=slowd_period)
return _first_col(r, "STOCHk_") if r is not None else _empty()
def _stoch_ta(d, df, fastk_period=14, **_):
from ta.momentum import StochasticOscillator
return _strip_nan(
StochasticOscillator(df["high"], df["low"], df["close"], window=fastk_period)
.stoch()
.values
)
def _stoch_tu(d, df, fastk_period=14, slowk_period=3, slowd_period=3, **_):
k, dd = _tl.stoch(
_c64(d["high"]),
_c64(d["low"]),
_c64(d["close"]),
pct_k_period=fastk_period,
pct_k_slowing_period=slowk_period,
pct_d_period=slowd_period,
)
return _strip_nan(k)
def _stoch_fi(d, df, fastk_period=14, **_):
return _strip_nan(_fi.STOCH(df, fastk_period).values)
def _cci_ft(d, df, timeperiod=14, **_):
import ferro_ta
return _strip_nan(
ferro_ta.CCI(d["high"], d["low"], d["close"], timeperiod=timeperiod)
)
def _cci_tl(d, df, timeperiod=14, **_):
return _strip_nan(
_talib.CCI(d["high"], d["low"], d["close"], timeperiod=timeperiod)
)
def _cci_pt(d, df, timeperiod=14, **_):
return _strip_nan(
_pta.cci(df["high"], df["low"], df["close"], length=timeperiod).values
)
def _cci_ta(d, df, timeperiod=14, **_):
from ta.trend import CCIIndicator
return _strip_nan(
CCIIndicator(df["high"], df["low"], df["close"], window=timeperiod).cci().values
)
def _cci_tu(d, df, timeperiod=14, **_):
return _strip_nan(
_tl.cci(_c64(d["high"]), _c64(d["low"]), _c64(d["close"]), period=timeperiod)
)
def _cci_fi(d, df, timeperiod=14, **_):
return _strip_nan(_fi.CCI(df, timeperiod).values)
def _willr_ft(d, df, timeperiod=14, **_):
import ferro_ta
return _strip_nan(
ferro_ta.WILLR(d["high"], d["low"], d["close"], timeperiod=timeperiod)
)
def _willr_tl(d, df, timeperiod=14, **_):
return _strip_nan(
_talib.WILLR(d["high"], d["low"], d["close"], timeperiod=timeperiod)
)
def _willr_pt(d, df, timeperiod=14, **_):
return _strip_nan(
_pta.willr(df["high"], df["low"], df["close"], length=timeperiod).values
)
def _willr_ta(d, df, timeperiod=14, **_):
from ta.momentum import WilliamsRIndicator
return _strip_nan(
WilliamsRIndicator(df["high"], df["low"], df["close"], lbp=timeperiod)
.williams_r()
.values
)
def _willr_tu(d, df, timeperiod=14, **_):
return _strip_nan(
_tl.willr(_c64(d["high"]), _c64(d["low"]), _c64(d["close"]), period=timeperiod)
)
def _willr_fi(d, df, timeperiod=14, **_):
return _strip_nan(_fi.WILLIAMS(df, timeperiod).values)
def _aroon_ft(d, df, timeperiod=14, **_):
import ferro_ta
dn, up = ferro_ta.AROON(d["high"], d["low"], timeperiod=timeperiod)
return _strip_nan(up)
def _aroon_tl(d, df, timeperiod=14, **_):
dn, up = _talib.AROON(d["high"], d["low"], timeperiod=timeperiod)
return _strip_nan(up)
def _aroon_pt(d, df, timeperiod=14, **_):
r = _pta.aroon(df["high"], df["low"], length=timeperiod)
return _first_col(r, "AROONU_") if r is not None else _empty()
def _aroon_ta(d, df, timeperiod=14, **_):
from ta.trend import AroonIndicator
return _strip_nan(
AroonIndicator(df["high"], df["low"], window=timeperiod).aroon_up().values
)
def _aroon_tu(d, df, timeperiod=14, **_):
dn, up = _tl.aroon(_c64(d["high"]), _c64(d["low"]), period=timeperiod)
return _strip_nan(up)
def _aroon_fi(d, df, **_):
return _empty()
_aroon_fi._stub = True
def _aroonosc_ft(d, df, timeperiod=14, **_):
import ferro_ta
return _strip_nan(ferro_ta.AROONOSC(d["high"], d["low"], timeperiod=timeperiod))
def _aroonosc_tl(d, df, timeperiod=14, **_):
return _strip_nan(_talib.AROONOSC(d["high"], d["low"], timeperiod=timeperiod))
def _aroonosc_pt(d, df, **_):
return _empty()
_aroonosc_pt._stub = True
def _aroonosc_ta(d, df, **_):
return _empty()
_aroonosc_ta._stub = True
def _aroonosc_tu(d, df, timeperiod=14, **_):
return _strip_nan(_tl.aroonosc(_c64(d["high"]), _c64(d["low"]), period=timeperiod))
def _aroonosc_fi(d, df, **_):
return _empty()
_aroonosc_fi._stub = True
def _adx_ft(d, df, timeperiod=14, **_):
import ferro_ta
return _strip_nan(
ferro_ta.ADX(d["high"], d["low"], d["close"], timeperiod=timeperiod)
)
def _adx_tl(d, df, timeperiod=14, **_):
return _strip_nan(
_talib.ADX(d["high"], d["low"], d["close"], timeperiod=timeperiod)
)
def _adx_pt(d, df, timeperiod=14, **_):
r = _pta.adx(df["high"], df["low"], df["close"], length=timeperiod)
return _first_col(r, "ADX_")
def _adx_ta(d, df, timeperiod=14, **_):
from ta.trend import ADXIndicator
return _strip_nan(
ADXIndicator(df["high"], df["low"], df["close"], window=timeperiod).adx().values
)
def _adx_tu(d, df, timeperiod=14, **_):
return _strip_nan(
_tl.adx(_c64(d["high"]), _c64(d["low"]), _c64(d["close"]), period=timeperiod)
)
def _adx_fi(d, df, **_):
return _empty()
_adx_fi._stub = True
def _mom_ft(d, df, timeperiod=10, **_):
import ferro_ta
return _strip_nan(ferro_ta.MOM(d["close"], timeperiod=timeperiod))
def _mom_tl(d, df, timeperiod=10, **_):
return _strip_nan(_talib.MOM(d["close"], timeperiod=timeperiod))
def _mom_pt(d, df, timeperiod=10, **_):
return _strip_nan(_pta.mom(df["close"], length=timeperiod).values)
def _mom_ta(d, df, **_):
return _empty()
_mom_ta._stub = True
def _mom_tu(d, df, timeperiod=10, **_):
return _strip_nan(_tl.mom(_c64(d["close"]), period=timeperiod))
def _mom_fi(d, df, timeperiod=10, **_):
return _strip_nan(_fi.MOM(df, timeperiod).values)
def _roc_ft(d, df, timeperiod=10, **_):
import ferro_ta
return _strip_nan(ferro_ta.ROC(d["close"], timeperiod=timeperiod))
def _roc_tl(d, df, timeperiod=10, **_):
return _strip_nan(_talib.ROC(d["close"], timeperiod=timeperiod))
def _roc_pt(d, df, timeperiod=10, **_):
return _strip_nan(_pta.roc(df["close"], length=timeperiod).values)
def _roc_ta(d, df, timeperiod=10, **_):
from ta.momentum import ROCIndicator
return _strip_nan(ROCIndicator(df["close"], window=timeperiod).roc().values)
def _roc_tu(d, df, timeperiod=10, **_):
return _strip_nan(_tl.roc(_c64(d["close"]), period=timeperiod) * 100.0)
def _roc_fi(d, df, timeperiod=10, **_):
return _strip_nan(_fi.ROC(df, timeperiod).values)
def _cmo_ft(d, df, timeperiod=14, **_):
import ferro_ta
return _strip_nan(ferro_ta.CMO(d["close"], timeperiod=timeperiod))
def _cmo_tl(d, df, timeperiod=14, **_):
return _strip_nan(_talib.CMO(d["close"], timeperiod=timeperiod))
def _cmo_pt(d, df, timeperiod=14, **_):
return _strip_nan(_pta.cmo(df["close"], length=timeperiod).values)
def _cmo_ta(d, df, **_):
return _empty()
_cmo_ta._stub = True
def _cmo_tu(d, df, timeperiod=14, **_):
return _strip_nan(_tl.cmo(_c64(d["close"]), period=timeperiod))
def _cmo_fi(d, df, timeperiod=14, **_):
return _strip_nan(_fi.CMO(df, timeperiod).values)
def _ppo_ft(d, df, fastperiod=12, slowperiod=26, **_):
import ferro_ta
ppo, sig, hist = ferro_ta.PPO(
d["close"], fastperiod=fastperiod, slowperiod=slowperiod
)
return _strip_nan(ppo)
def _ppo_tl(d, df, fastperiod=12, slowperiod=26, **_):
return _strip_nan(
_talib.PPO(d["close"], fastperiod=fastperiod, slowperiod=slowperiod)
)
def _ppo_pt(d, df, fastperiod=12, slowperiod=26, **_):
r = _pta.ppo(df["close"], fast=fastperiod, slow=slowperiod)
return _strip_nan(r.iloc[:, 0].values) if r is not None else _empty()
def _ppo_ta(d, df, **_):
return _empty()
_ppo_ta._stub = True
def _ppo_tu(d, df, fastperiod=12, slowperiod=26, **_):
return _strip_nan(
_tl.ppo(_c64(d["close"]), short_period=fastperiod, long_period=slowperiod)
)
def _ppo_fi(d, df, fastperiod=12, slowperiod=26, **_):
return _strip_nan(_fi.PPO(df, fastperiod, slowperiod).values)
def _trix_ft(d, df, timeperiod=18, **_):
import ferro_ta
return _strip_nan(ferro_ta.TRIX(d["close"], timeperiod=timeperiod))
def _trix_tl(d, df, timeperiod=18, **_):
return _strip_nan(_talib.TRIX(d["close"], timeperiod=timeperiod))
def _trix_pt(d, df, timeperiod=18, **_):
r = _pta.trix(df["close"], length=timeperiod)
return _strip_nan(r.iloc[:, 0].values) if r is not None else _empty()
def _trix_ta(d, df, timeperiod=18, **_):
from ta.trend import TRIXIndicator
return _strip_nan(TRIXIndicator(df["close"], window=timeperiod).trix().values)
def _trix_tu(d, df, timeperiod=18, **_):
return _strip_nan(_tl.trix(_c64(d["close"]), period=timeperiod))
def _trix_fi(d, df, timeperiod=18, **_):
return _strip_nan(_fi.TRIX(df, timeperiod).values)
def _tsf_ft(d, df, timeperiod=14, **_):
import ferro_ta
return _strip_nan(ferro_ta.TSF(d["close"], timeperiod=timeperiod))
def _tsf_tl(d, df, timeperiod=14, **_):
return _strip_nan(_talib.TSF(d["close"], timeperiod=timeperiod))
def _tsf_pt(d, df, **_):
return _empty()
_tsf_pt._stub = True
def _tsf_ta(d, df, **_):
return _empty()
_tsf_ta._stub = True
def _tsf_tu(d, df, timeperiod=14, **_):
return _strip_nan(_tl.tsf(_c64(d["close"]), period=timeperiod))
def _tsf_fi(d, df, **_):
return _empty()
_tsf_fi._stub = True
def _ultosc_ft(d, df, timeperiod1=7, timeperiod2=14, timeperiod3=28, **_):
import ferro_ta
return _strip_nan(
ferro_ta.ULTOSC(
d["high"],
d["low"],
d["close"],
timeperiod1=timeperiod1,
timeperiod2=timeperiod2,
timeperiod3=timeperiod3,
)
)
def _ultosc_tl(d, df, timeperiod1=7, timeperiod2=14, timeperiod3=28, **_):
return _strip_nan(
_talib.ULTOSC(
d["high"],
d["low"],
d["close"],
timeperiod1=timeperiod1,
timeperiod2=timeperiod2,
timeperiod3=timeperiod3,
)
)
def _ultosc_pt(d, df, **_):
return _empty()
_ultosc_pt._stub = True
def _ultosc_ta(d, df, timeperiod1=7, timeperiod2=14, timeperiod3=28, **_):
from ta.momentum import UltimateOscillator
return _strip_nan(
UltimateOscillator(
df["high"],
df["low"],
df["close"],
window1=timeperiod1,
window2=timeperiod2,
window3=timeperiod3,
)
.ultimate_oscillator()
.values
)
def _ultosc_tu(d, df, timeperiod1=7, timeperiod2=14, timeperiod3=28, **_):
return _strip_nan(
_tl.ultosc(
_c64(d["high"]),
_c64(d["low"]),
_c64(d["close"]),
short_period=timeperiod1,
medium_period=timeperiod2,
long_period=timeperiod3,
)
)
def _ultosc_fi(d, df, **_):
return _empty()
_ultosc_fi._stub = True
def _bop_ft(d, df, **_):
import ferro_ta
return _strip_nan(ferro_ta.BOP(d["open"], d["high"], d["low"], d["close"]))
def _bop_tl(d, df, **_):
return _strip_nan(_talib.BOP(d["open"], d["high"], d["low"], d["close"]))
def _bop_pt(d, df, **_):
r = _pta.bop(df["open"], df["high"], df["low"], df["close"])
return _strip_nan(r.values) if r is not None else _empty()
def _bop_ta(d, df, **_):
return _empty()
_bop_ta._stub = True
def _bop_tu(d, df, **_):
return _strip_nan(
_tl.bop(_c64(d["open"]), _c64(d["high"]), _c64(d["low"]), _c64(d["close"]))
)
def _bop_fi(d, df, **_):
return _empty()
_bop_fi._stub = True
def _plusdi_ft(d, df, timeperiod=14, **_):
import ferro_ta
return _strip_nan(
ferro_ta.PLUS_DI(d["high"], d["low"], d["close"], timeperiod=timeperiod)
)
def _plusdi_tl(d, df, timeperiod=14, **_):
return _strip_nan(
_talib.PLUS_DI(d["high"], d["low"], d["close"], timeperiod=timeperiod)
)
def _plusdi_pt(d, df, timeperiod=14, **_):
r = _pta.adx(df["high"], df["low"], df["close"], length=timeperiod)
return _first_col(r, "DMP_") if r is not None else _empty()
def _plusdi_ta(d, df, **_):
return _empty()
_plusdi_ta._stub = True
def _plusdi_tu(d, df, timeperiod=14, **_):
pdi, mdi = _tl.di(
_c64(d["high"]), _c64(d["low"]), _c64(d["close"]), period=timeperiod
)
return _strip_nan(pdi)
def _plusdi_fi(d, df, **_):
return _empty()
_plusdi_fi._stub = True
def _minusdi_ft(d, df, timeperiod=14, **_):
import ferro_ta
return _strip_nan(
ferro_ta.MINUS_DI(d["high"], d["low"], d["close"], timeperiod=timeperiod)
)
def _minusdi_tl(d, df, timeperiod=14, **_):
return _strip_nan(
_talib.MINUS_DI(d["high"], d["low"], d["close"], timeperiod=timeperiod)
)
def _minusdi_pt(d, df, **_):
return _empty()
_minusdi_pt._stub = True
def _minusdi_ta(d, df, **_):
return _empty()
_minusdi_ta._stub = True
def _minusdi_tu(d, df, timeperiod=14, **_):
pdi, mdi = _tl.di(
_c64(d["high"]), _c64(d["low"]), _c64(d["close"]), period=timeperiod
)
return _strip_nan(mdi)
def _minusdi_fi(d, df, **_):
return _empty()
_minusdi_fi._stub = True
# ============================================================
# VOLATILITY
# ============================================================
def _bb_ft(d, df, timeperiod=20, nbdevup=2.0, nbdevdn=2.0, **_):
import ferro_ta
u, m, l = ferro_ta.BBANDS(
d["close"], timeperiod=timeperiod, nbdevup=nbdevup, nbdevdn=nbdevdn
)
return _strip_nan(u)
def _bb_tl(d, df, timeperiod=20, nbdevup=2.0, nbdevdn=2.0, **_):
u, m, l = _talib.BBANDS(
d["close"], timeperiod=timeperiod, nbdevup=nbdevup, nbdevdn=nbdevdn
)
return _strip_nan(u)
def _bb_pt(d, df, timeperiod=20, nbdevup=2.0, **_):
r = _pta.bbands(df["close"], length=timeperiod, std=nbdevup)
return _first_col(r, "BBU_")
def _bb_ta(d, df, timeperiod=20, nbdevup=2.0, **_):
from ta.volatility import BollingerBands
return _strip_nan(
BollingerBands(df["close"], window=timeperiod, window_dev=nbdevup)
.bollinger_hband()
.values
)
def _bb_tu(d, df, timeperiod=20, nbdevup=2.0, **_):
lo, mi, up = _tl.bbands(_c64(d["close"]), period=timeperiod, stddev=nbdevup)
return _strip_nan(up)
def _bb_fi(d, df, timeperiod=20, **_):
return _strip_nan(_fi.BBANDS(df, timeperiod)["BB_UPPER"].values)
def _atr_ft(d, df, timeperiod=14, **_):
import ferro_ta
return _strip_nan(
ferro_ta.ATR(d["high"], d["low"], d["close"], timeperiod=timeperiod)
)
def _atr_tl(d, df, timeperiod=14, **_):
return _strip_nan(
_talib.ATR(d["high"], d["low"], d["close"], timeperiod=timeperiod)
)
def _atr_pt(d, df, timeperiod=14, **_):
return _strip_nan(
_pta.atr(df["high"], df["low"], df["close"], length=timeperiod).values
)
def _atr_ta(d, df, timeperiod=14, **_):
from ta.volatility import AverageTrueRange
return _strip_nan(
AverageTrueRange(df["high"], df["low"], df["close"], window=timeperiod)
.average_true_range()
.values
)
def _atr_tu(d, df, timeperiod=14, **_):
return _strip_nan(
_tl.atr(_c64(d["high"]), _c64(d["low"]), _c64(d["close"]), period=timeperiod)
)
def _atr_fi(d, df, timeperiod=14, **_):
return _strip_nan(_fi.ATR(df, timeperiod).values)
def _natr_ft(d, df, timeperiod=14, **_):
import ferro_ta
return _strip_nan(
ferro_ta.NATR(d["high"], d["low"], d["close"], timeperiod=timeperiod)
)
def _natr_tl(d, df, timeperiod=14, **_):
return _strip_nan(
_talib.NATR(d["high"], d["low"], d["close"], timeperiod=timeperiod)
)
def _natr_pt(d, df, timeperiod=14, **_):
return _strip_nan(
_pta.natr(df["high"], df["low"], df["close"], length=timeperiod).values
)
def _natr_ta(d, df, **_):
return _empty()
_natr_ta._stub = True
def _natr_tu(d, df, timeperiod=14, **_):
return _strip_nan(
_tl.natr(_c64(d["high"]), _c64(d["low"]), _c64(d["close"]), period=timeperiod)
)
def _natr_fi(d, df, **_):
return _empty()
_natr_fi._stub = True
def _trange_ft(d, df, **_):
import ferro_ta
return _strip_nan(ferro_ta.TRANGE(d["high"], d["low"], d["close"]))
def _trange_tl(d, df, **_):
return _strip_nan(_talib.TRANGE(d["high"], d["low"], d["close"]))
def _trange_pt(d, df, **_):
r = _pta.true_range(df["high"], df["low"], df["close"])
return _strip_nan(r.values) if r is not None else _empty()
def _trange_ta(d, df, **_):
return _empty()
_trange_ta._stub = True
def _trange_tu(d, df, **_):
return _strip_nan(_tl.tr(_c64(d["high"]), _c64(d["low"]), _c64(d["close"])))
def _trange_fi(d, df, **_):
return _strip_nan(_fi.TR(df).values)
def _stddev_ft(d, df, timeperiod=20, **_):
import ferro_ta
return _strip_nan(ferro_ta.STDDEV(d["close"], timeperiod=timeperiod))
def _stddev_tl(d, df, timeperiod=20, **_):
return _strip_nan(_talib.STDDEV(d["close"], timeperiod=timeperiod))
def _stddev_pt(d, df, timeperiod=20, **_):
r = _pta.stdev(df["close"], length=timeperiod)
return _strip_nan(r.values) if r is not None else _empty()
def _stddev_ta(d, df, **_):
return _empty()
_stddev_ta._stub = True
def _stddev_tu(d, df, timeperiod=20, **_):
return _strip_nan(_tl.stddev(_c64(d["close"]), period=timeperiod))
def _stddev_fi(d, df, timeperiod=20, **_):
return _strip_nan(_fi.MSD(df, timeperiod).values)
def _var_ft(d, df, timeperiod=20, **_):
import ferro_ta
return _strip_nan(ferro_ta.VAR(d["close"], timeperiod=timeperiod))
def _var_tl(d, df, timeperiod=20, **_):
return _strip_nan(_talib.VAR(d["close"], timeperiod=timeperiod))
def _var_pt(d, df, timeperiod=20, **_):
r = _pta.variance(df["close"], length=timeperiod)
return _strip_nan(r.values) if r is not None else _empty()
def _var_ta(d, df, **_):
return _empty()
_var_ta._stub = True
def _var_tu(d, df, timeperiod=20, **_):
return _strip_nan(_tl.var(_c64(d["close"]), period=timeperiod))
def _var_fi(d, df, **_):
return _empty()
_var_fi._stub = True
def _sar_ft(d, df, acceleration=0.02, maximum=0.2, **_):
import ferro_ta
return _strip_nan(
ferro_ta.SAR(d["high"], d["low"], acceleration=acceleration, maximum=maximum)
)
def _sar_tl(d, df, acceleration=0.02, maximum=0.2, **_):
return _strip_nan(
_talib.SAR(d["high"], d["low"], acceleration=acceleration, maximum=maximum)
)
def _sar_pt(d, df, **_):
return _empty()
_sar_pt._stub = True
def _sar_ta(d, df, **_):
return _empty()
_sar_ta._stub = True
def _sar_tu(d, df, acceleration=0.02, maximum=0.2, **_):
return _strip_nan(
_tl.psar(
_c64(d["high"]),
_c64(d["low"]),
acceleration_factor_step=acceleration,
acceleration_factor_maximum=maximum,
)
)
def _sar_fi(d, df, **_):
return _empty()
_sar_fi._stub = True
def _kc_ft(d, df, timeperiod=20, **_):
import ferro_ta
u, m, l = ferro_ta.KELTNER_CHANNELS(
d["high"], d["low"], d["close"], timeperiod=timeperiod
)
return _strip_nan(u)
def _kc_tl(d, df, **_):
return _empty()
_kc_tl._stub = True
def _kc_pt(d, df, timeperiod=20, **_):
r = _pta.kc(df["high"], df["low"], df["close"], length=timeperiod)
if r is None:
return _empty()
col = next(
(c for c in r.columns if "UCe" in c or "UB" in c or c.endswith("U")), None
)
return _strip_nan(r[col].values) if col else _first_col(r, "KC")
def _kc_ta(d, df, timeperiod=20, **_):
from ta.volatility import KeltnerChannel
return _strip_nan(
KeltnerChannel(df["high"], df["low"], df["close"], window=timeperiod)
.keltner_channel_hband()
.values
)
def _kc_tu(d, df, **_):
return _empty()
_kc_tu._stub = True
def _kc_fi(d, df, **_):
return _empty()
_kc_fi._stub = True
def _donchian_ft(d, df, timeperiod=20, **_):
import ferro_ta
u, m, l = ferro_ta.DONCHIAN(d["high"], d["low"], timeperiod=timeperiod)
return _strip_nan(u)
def _donchian_tl(d, df, **_):
return _empty()
_donchian_tl._stub = True
def _donchian_pt(d, df, timeperiod=20, **_):
r = _pta.donchian(
df["high"], df["low"], lower_length=timeperiod, upper_length=timeperiod
)
return _first_col(r, "DCU_") if r is not None else _empty()
def _donchian_ta(d, df, timeperiod=20, **_):
from ta.volatility import DonchianChannel
return _strip_nan(
DonchianChannel(df["high"], df["low"], df["close"], window=timeperiod)
.donchian_channel_hband()
.values
)
def _donchian_tu(d, df, **_):
return _empty()
_donchian_tu._stub = True
def _donchian_fi(d, df, **_):
return _empty()
_donchian_fi._stub = True
def _supertrend_ft(d, df, timeperiod=7, **_):
import ferro_ta
st, dir_ = ferro_ta.SUPERTREND(
d["high"], d["low"], d["close"], timeperiod=timeperiod
)
return _strip_nan(st)
def _supertrend_tl(d, df, **_):
return _empty()
_supertrend_tl._stub = True
def _supertrend_pt(d, df, timeperiod=7, **_):
r = _pta.supertrend(df["high"], df["low"], df["close"], length=timeperiod)
return _first_col(r, "SUPERT_") if r is not None else _empty()
def _supertrend_ta(d, df, **_):
return _empty()
_supertrend_ta._stub = True
def _supertrend_tu(d, df, **_):
return _empty()
_supertrend_tu._stub = True
def _supertrend_fi(d, df, **_):
return _empty()
_supertrend_fi._stub = True
def _chop_ft(d, df, timeperiod=14, **_):
import ferro_ta
return _strip_nan(
ferro_ta.CHOPPINESS_INDEX(
d["high"], d["low"], d["close"], timeperiod=timeperiod
)
)
def _chop_tl(d, df, **_):
return _empty()
_chop_tl._stub = True
def _chop_pt(d, df, timeperiod=14, **_):
r = _pta.chop(df["high"], df["low"], df["close"], length=timeperiod)
return _strip_nan(r.values) if r is not None else _empty()
def _chop_ta(d, df, **_):
return _empty()
_chop_ta._stub = True
def _chop_tu(d, df, **_):
return _empty()
_chop_tu._stub = True
def _chop_fi(d, df, **_):
return _empty()
_chop_fi._stub = True
# ============================================================
# VOLUME
# ============================================================
def _obv_ft(d, df, **_):
import ferro_ta
return _strip_nan(ferro_ta.OBV(d["close"], d["volume"]))
def _obv_tl(d, df, **_):
return _strip_nan(_talib.OBV(d["close"], d["volume"]))
def _obv_pt(d, df, **_):
return _strip_nan(_pta.obv(df["close"], df["volume"]).values)
def _obv_ta(d, df, **_):
from ta.volume import OnBalanceVolumeIndicator
return _strip_nan(
OnBalanceVolumeIndicator(df["close"], df["volume"]).on_balance_volume().values
)
def _obv_tu(d, df, **_):
return _strip_nan(_tl.obv(_c64(d["close"]), _c64(d["volume"])))
def _obv_fi(d, df, **_):
return _strip_nan(_fi.OBV(df).values)
def _ad_ft(d, df, **_):
import ferro_ta
return _strip_nan(ferro_ta.AD(d["high"], d["low"], d["close"], d["volume"]))
def _ad_tl(d, df, **_):
return _strip_nan(_talib.AD(d["high"], d["low"], d["close"], d["volume"]))
def _ad_pt(d, df, **_):
return _strip_nan(_pta.ad(df["high"], df["low"], df["close"], df["volume"]).values)
def _ad_ta(d, df, **_):
from ta.volume import AccDistIndexIndicator
return _strip_nan(
AccDistIndexIndicator(df["high"], df["low"], df["close"], df["volume"])
.acc_dist_index()
.values
)
def _ad_tu(d, df, **_):
return _strip_nan(
_tl.ad(_c64(d["high"]), _c64(d["low"]), _c64(d["close"]), _c64(d["volume"]))
)
def _ad_fi(d, df, **_):
return _empty()
_ad_fi._stub = True
def _adosc_ft(d, df, fastperiod=3, slowperiod=10, **_):
import ferro_ta
return _strip_nan(
ferro_ta.ADOSC(
d["high"],
d["low"],
d["close"],
d["volume"],
fastperiod=fastperiod,
slowperiod=slowperiod,
)
)
def _adosc_tl(d, df, fastperiod=3, slowperiod=10, **_):
return _strip_nan(
_talib.ADOSC(
d["high"],
d["low"],
d["close"],
d["volume"],
fastperiod=fastperiod,
slowperiod=slowperiod,
)
)
def _adosc_pt(d, df, fastperiod=3, slowperiod=10, **_):
return _strip_nan(
_pta.adosc(
df["high"],
df["low"],
df["close"],
df["volume"],
fast=fastperiod,
slow=slowperiod,
).values
)
def _adosc_ta(d, df, **_):
return _empty()
_adosc_ta._stub = True
def _adosc_tu(d, df, fastperiod=3, slowperiod=10, **_):
return _strip_nan(
_tl.adosc(
_c64(d["high"]),
_c64(d["low"]),
_c64(d["close"]),
_c64(d["volume"]),
short_period=fastperiod,
long_period=slowperiod,
)
)
def _adosc_fi(d, df, **_):
return _empty()
_adosc_fi._stub = True
def _mfi_ft(d, df, timeperiod=14, **_):
import ferro_ta
return _strip_nan(
ferro_ta.MFI(
d["high"], d["low"], d["close"], d["volume"], timeperiod=timeperiod
)
)
def _mfi_tl(d, df, timeperiod=14, **_):
return _strip_nan(
_talib.MFI(d["high"], d["low"], d["close"], d["volume"], timeperiod=timeperiod)
)
def _mfi_pt(d, df, timeperiod=14, **_):
return _strip_nan(
_pta.mfi(
df["high"], df["low"], df["close"], df["volume"], length=timeperiod
).values
)
def _mfi_ta(d, df, timeperiod=14, **_):
from ta.volume import MFIIndicator
return _strip_nan(
MFIIndicator(
df["high"], df["low"], df["close"], df["volume"], window=timeperiod
)
.money_flow_index()
.values
)
def _mfi_tu(d, df, timeperiod=14, **_):
return _strip_nan(
_tl.mfi(
_c64(d["high"]),
_c64(d["low"]),
_c64(d["close"]),
_c64(d["volume"]),
period=timeperiod,
)
)
def _mfi_fi(d, df, timeperiod=14, **_):
return _strip_nan(_fi.MFI(df, timeperiod).values)
def _vwap_ft(d, df, **_):
import ferro_ta
return _strip_nan(ferro_ta.VWAP(d["high"], d["low"], d["close"], d["volume"]))
def _vwap_tl(d, df, **_):
return _empty()
_vwap_tl._stub = True
def _vwap_pt(d, df, **_):
r = _pta.vwap(df["high"], df["low"], df["close"], df["volume"])
return _strip_nan(r.values) if r is not None else _empty()
def _vwap_ta(d, df, **_):
return _empty()
_vwap_ta._stub = True
def _vwap_tu(d, df, **_):
return _empty()
_vwap_tu._stub = True
def _vwap_fi(d, df, **_):
return _strip_nan(_fi.VWAP(df).values)
# ============================================================
# PRICE TRANSFORM
# ============================================================
def _avgprice_ft(d, df, **_):
import ferro_ta
return _strip_nan(ferro_ta.AVGPRICE(d["open"], d["high"], d["low"], d["close"]))
def _avgprice_tl(d, df, **_):
return _strip_nan(_talib.AVGPRICE(d["open"], d["high"], d["low"], d["close"]))
def _avgprice_pt(d, df, **_):
return _empty()
_avgprice_pt._stub = True
def _avgprice_ta(d, df, **_):
return _empty()
_avgprice_ta._stub = True
def _avgprice_tu(d, df, **_):
return _strip_nan(
_tl.avgprice(_c64(d["open"]), _c64(d["high"]), _c64(d["low"]), _c64(d["close"]))
)
def _avgprice_fi(d, df, **_):
return _empty()
_avgprice_fi._stub = True
def _medprice_ft(d, df, **_):
import ferro_ta
return _strip_nan(ferro_ta.MEDPRICE(d["high"], d["low"]))
def _medprice_tl(d, df, **_):
return _strip_nan(_talib.MEDPRICE(d["high"], d["low"]))
def _medprice_pt(d, df, **_):
return _empty()
_medprice_pt._stub = True
def _medprice_ta(d, df, **_):
return _empty()
_medprice_ta._stub = True
def _medprice_tu(d, df, **_):
return _strip_nan(_tl.medprice(_c64(d["high"]), _c64(d["low"])))
def _medprice_fi(d, df, **_):
return _empty()
_medprice_fi._stub = True
def _typprice_ft(d, df, **_):
import ferro_ta
return _strip_nan(ferro_ta.TYPPRICE(d["high"], d["low"], d["close"]))
def _typprice_tl(d, df, **_):
return _strip_nan(_talib.TYPPRICE(d["high"], d["low"], d["close"]))
def _typprice_pt(d, df, **_):
return _empty()
_typprice_pt._stub = True
def _typprice_ta(d, df, **_):
return _empty()
_typprice_ta._stub = True
def _typprice_tu(d, df, **_):
return _strip_nan(_tl.typprice(_c64(d["high"]), _c64(d["low"]), _c64(d["close"])))
def _typprice_fi(d, df, **_):
return _empty()
_typprice_fi._stub = True
def _wclprice_ft(d, df, **_):
import ferro_ta
return _strip_nan(ferro_ta.WCLPRICE(d["high"], d["low"], d["close"]))
def _wclprice_tl(d, df, **_):
return _strip_nan(_talib.WCLPRICE(d["high"], d["low"], d["close"]))
def _wclprice_pt(d, df, **_):
return _empty()
_wclprice_pt._stub = True
def _wclprice_ta(d, df, **_):
return _empty()
_wclprice_ta._stub = True
def _wclprice_tu(d, df, **_):
return _strip_nan(_tl.wcprice(_c64(d["high"]), _c64(d["low"]), _c64(d["close"])))
def _wclprice_fi(d, df, **_):
return _empty()
_wclprice_fi._stub = True
# ============================================================
# MATH
# ============================================================
def _sqrt_ft(d, df, **_):
import ferro_ta
return _strip_nan(ferro_ta.SQRT(d["close"]))
def _sqrt_tl(d, df, **_):
return _strip_nan(_talib.SQRT(d["close"]))
def _sqrt_pt(d, df, **_):
return _empty()
_sqrt_pt._stub = True
def _sqrt_ta(d, df, **_):
return _empty()
_sqrt_ta._stub = True
def _sqrt_tu(d, df, **_):
return _strip_nan(_tl.sqrt(_c64(d["close"])))
def _sqrt_fi(d, df, **_):
return _empty()
_sqrt_fi._stub = True
def _log10_ft(d, df, **_):
import ferro_ta
return _strip_nan(ferro_ta.LOG10(d["close"]))
def _log10_tl(d, df, **_):
return _strip_nan(_talib.LOG10(d["close"]))
def _log10_pt(d, df, **_):
return _empty()
_log10_pt._stub = True
def _log10_ta(d, df, **_):
return _empty()
_log10_ta._stub = True
def _log10_tu(d, df, **_):
return _strip_nan(_tl.log10(_c64(d["close"])))
def _log10_fi(d, df, **_):
return _empty()
_log10_fi._stub = True
def _add_ft(d, df, **_):
import ferro_ta
return _strip_nan(ferro_ta.ADD(d["high"], d["low"]))
def _add_tl(d, df, **_):
return _strip_nan(_talib.ADD(d["high"], d["low"]))
def _add_pt(d, df, **_):
return _empty()
_add_pt._stub = True
def _add_ta(d, df, **_):
return _empty()
_add_ta._stub = True
def _add_tu(d, df, **_):
return _strip_nan(_tl.add(_c64(d["high"]), _c64(d["low"])))
def _add_fi(d, df, **_):
return _empty()
_add_fi._stub = True
# ============================================================
# STATISTICS
# ============================================================
def _linearreg_ft(d, df, timeperiod=14, **_):
import ferro_ta
return _strip_nan(ferro_ta.LINEARREG(d["close"], timeperiod=timeperiod))
def _linearreg_tl(d, df, timeperiod=14, **_):
return _strip_nan(_talib.LINEARREG(d["close"], timeperiod=timeperiod))
def _linearreg_pt(d, df, **_):
return _empty()
_linearreg_pt._stub = True
def _linearreg_ta(d, df, **_):
return _empty()
_linearreg_ta._stub = True
def _linearreg_tu(d, df, timeperiod=14, **_):
return _strip_nan(_tl.linreg(_c64(d["close"]), period=timeperiod))
def _linearreg_fi(d, df, **_):
return _empty()
_linearreg_fi._stub = True
def _linreg_slope_ft(d, df, timeperiod=14, **_):
import ferro_ta
return _strip_nan(ferro_ta.LINEARREG_SLOPE(d["close"], timeperiod=timeperiod))
def _linreg_slope_tl(d, df, timeperiod=14, **_):
return _strip_nan(_talib.LINEARREG_SLOPE(d["close"], timeperiod=timeperiod))
def _linreg_slope_pt(d, df, **_):
return _empty()
_linreg_slope_pt._stub = True
def _linreg_slope_ta(d, df, **_):
return _empty()
_linreg_slope_ta._stub = True
def _linreg_slope_tu(d, df, timeperiod=14, **_):
return _strip_nan(_tl.linregslope(_c64(d["close"]), period=timeperiod))
def _linreg_slope_fi(d, df, **_):
return _empty()
_linreg_slope_fi._stub = True
def _correl_ft(d, df, timeperiod=30, **_):
import ferro_ta
return _strip_nan(ferro_ta.CORREL(d["high"], d["low"], timeperiod=timeperiod))
def _correl_tl(d, df, timeperiod=30, **_):
return _strip_nan(_talib.CORREL(d["high"], d["low"], timeperiod=timeperiod))
def _correl_pt(d, df, **_):
return _empty()
_correl_pt._stub = True
def _correl_ta(d, df, **_):
return _empty()
_correl_ta._stub = True
def _correl_tu(d, df, **_):
return _empty()
_correl_tu._stub = True
def _correl_fi(d, df, **_):
return _empty()
_correl_fi._stub = True
def _beta_ft(d, df, timeperiod=5, **_):
import ferro_ta
return _strip_nan(ferro_ta.BETA(d["high"], d["low"], timeperiod=timeperiod))
def _beta_tl(d, df, timeperiod=5, **_):
return _strip_nan(_talib.BETA(d["high"], d["low"], timeperiod=timeperiod))
def _beta_pt(d, df, **_):
return _empty()
_beta_pt._stub = True
def _beta_ta(d, df, **_):
return _empty()
_beta_ta._stub = True
def _beta_tu(d, df, **_):
return _empty()
_beta_tu._stub = True
def _beta_fi(d, df, **_):
return _empty()
_beta_fi._stub = True
# ============================================================
# CYCLE
# ============================================================
def _ht_dcperiod_ft(d, df, **_):
import ferro_ta
return _strip_nan(ferro_ta.HT_DCPERIOD(d["close"]))
def _ht_dcperiod_tl(d, df, **_):
return _strip_nan(_talib.HT_DCPERIOD(d["close"]))
def _ht_dcperiod_pt(d, df, **_):
return _empty()
_ht_dcperiod_pt._stub = True
def _ht_dcperiod_ta(d, df, **_):
return _empty()
_ht_dcperiod_ta._stub = True
def _ht_dcperiod_tu(d, df, **_):
return _empty()
_ht_dcperiod_tu._stub = True
def _ht_dcperiod_fi(d, df, **_):
return _empty()
_ht_dcperiod_fi._stub = True
def _ht_trendmode_ft(d, df, **_):
import ferro_ta
return _strip_nan(ferro_ta.HT_TRENDMODE(d["close"]).astype(float))
def _ht_trendmode_tl(d, df, **_):
return _strip_nan(_talib.HT_TRENDMODE(d["close"]).astype(float))
def _ht_trendmode_pt(d, df, **_):
return _empty()
_ht_trendmode_pt._stub = True
def _ht_trendmode_ta(d, df, **_):
return _empty()
_ht_trendmode_ta._stub = True
def _ht_trendmode_tu(d, df, **_):
return _empty()
_ht_trendmode_tu._stub = True
def _ht_trendmode_fi(d, df, **_):
return _empty()
_ht_trendmode_fi._stub = True
# ============================================================
# CANDLESTICK PATTERNS
# ============================================================
def _cdlengulfing_ft(d, df, **_):
import ferro_ta
return _strip_nan(
ferro_ta.CDLENGULFING(d["open"], d["high"], d["low"], d["close"]).astype(float)
)
def _cdlengulfing_tl(d, df, **_):
return _strip_nan(
_talib.CDLENGULFING(d["open"], d["high"], d["low"], d["close"]).astype(float)
)
def _cdlengulfing_pt(d, df, **_):
return _empty()
_cdlengulfing_pt._stub = True
def _cdlengulfing_ta(d, df, **_):
return _empty()
_cdlengulfing_ta._stub = True
def _cdlengulfing_tu(d, df, **_):
return _empty()
_cdlengulfing_tu._stub = True
def _cdlengulfing_fi(d, df, **_):
return _empty()
_cdlengulfing_fi._stub = True
def _cdldoji_ft(d, df, **_):
import ferro_ta
return _strip_nan(
ferro_ta.CDLDOJI(d["open"], d["high"], d["low"], d["close"]).astype(float)
)
def _cdldoji_tl(d, df, **_):
return _strip_nan(
_talib.CDLDOJI(d["open"], d["high"], d["low"], d["close"]).astype(float)
)
def _cdldoji_pt(d, df, **_):
return _empty()
_cdldoji_pt._stub = True
def _cdldoji_ta(d, df, **_):
return _empty()
_cdldoji_ta._stub = True
def _cdldoji_tu(d, df, **_):
return _empty()
_cdldoji_tu._stub = True
def _cdldoji_fi(d, df, **_):
return _empty()
_cdldoji_fi._stub = True
def _cdlhammer_ft(d, df, **_):
import ferro_ta
return _strip_nan(
ferro_ta.CDLHAMMER(d["open"], d["high"], d["low"], d["close"]).astype(float)
)
def _cdlhammer_tl(d, df, **_):
return _strip_nan(
_talib.CDLHAMMER(d["open"], d["high"], d["low"], d["close"]).astype(float)
)
def _cdlhammer_pt(d, df, **_):
return _empty()
_cdlhammer_pt._stub = True
def _cdlhammer_ta(d, df, **_):
return _empty()
_cdlhammer_ta._stub = True
def _cdlhammer_tu(d, df, **_):
return _empty()
_cdlhammer_tu._stub = True
def _cdlhammer_fi(d, df, **_):
return _empty()
_cdlhammer_fi._stub = True
# ============================================================
# REGISTRY BUILD
# ============================================================
REGISTRY: dict[tuple[str, Any], Any] = {}
def _reg(ind, ft, tl, pt, ta_, tu, fi):
"""
Register wrappers for a given indicator across all libraries.
Wrappers marked ._stub = True (no-op return _empty()) are not registered,
so execute_indicator raises KeyError for unsupported (lib, ind). Speed
benchmarks then skip those pairs and the table shows N/A.
"""
for lib, fn in [
("ferro_ta", ft),
("talib", tl),
("pandas_ta", pt),
("ta", ta_),
("tulipy", tu),
("finta", fi),
]:
if getattr(fn, "_stub", False):
continue
REGISTRY[(lib, ind)] = fn
_reg("SMA", _sma_ft, _sma_tl, _sma_pt, _sma_ta, _sma_tu, _sma_fi)
_reg("EMA", _ema_ft, _ema_tl, _ema_pt, _ema_ta, _ema_tu, _ema_fi)
_reg("WMA", _wma_ft, _wma_tl, _wma_pt, _wma_ta, _wma_tu, _wma_fi)
_reg("DEMA", _dema_ft, _dema_tl, _dema_pt, _dema_ta, _dema_tu, _dema_fi)
_reg("TEMA", _tema_ft, _tema_tl, _tema_pt, _tema_ta, _tema_tu, _tema_fi)
_reg("T3", _t3_ft, _t3_tl, _t3_pt, _t3_ta, _t3_tu, _t3_fi)
_reg("TRIMA", _trima_ft, _trima_tl, _trima_pt, _trima_ta, _trima_tu, _trima_fi)
_reg("KAMA", _kama_ft, _kama_tl, _kama_pt, _kama_ta, _kama_tu, _kama_fi)
_reg("HULL_MA", _hma_ft, _hma_tl, _hma_pt, _hma_ta, _hma_tu, _hma_fi)
_reg("VWMA", _vwma_ft, _vwma_tl, _vwma_pt, _vwma_ta, _vwma_tu, _vwma_fi)
_reg(
"MIDPOINT",
_midpoint_ft,
_midpoint_tl,
_midpoint_pt,
_midpoint_ta,
_midpoint_tu,
_midpoint_fi,
)
_reg(
"MIDPRICE",
_midprice_ft,
_midprice_tl,
_midprice_pt,
_midprice_ta,
_midprice_tu,
_midprice_fi,
)
_reg("RSI", _rsi_ft, _rsi_tl, _rsi_pt, _rsi_ta, _rsi_tu, _rsi_fi)
_reg("MACD", _macd_ft, _macd_tl, _macd_pt, _macd_ta, _macd_tu, _macd_fi)
_reg("STOCH", _stoch_ft, _stoch_tl, _stoch_pt, _stoch_ta, _stoch_tu, _stoch_fi)
_reg("CCI", _cci_ft, _cci_tl, _cci_pt, _cci_ta, _cci_tu, _cci_fi)
_reg("WILLR", _willr_ft, _willr_tl, _willr_pt, _willr_ta, _willr_tu, _willr_fi)
_reg("AROON", _aroon_ft, _aroon_tl, _aroon_pt, _aroon_ta, _aroon_tu, _aroon_fi)
_reg(
"AROONOSC",
_aroonosc_ft,
_aroonosc_tl,
_aroonosc_pt,
_aroonosc_ta,
_aroonosc_tu,
_aroonosc_fi,
)
_reg("ADX", _adx_ft, _adx_tl, _adx_pt, _adx_ta, _adx_tu, _adx_fi)
_reg("MOM", _mom_ft, _mom_tl, _mom_pt, _mom_ta, _mom_tu, _mom_fi)
_reg("ROC", _roc_ft, _roc_tl, _roc_pt, _roc_ta, _roc_tu, _roc_fi)
_reg("CMO", _cmo_ft, _cmo_tl, _cmo_pt, _cmo_ta, _cmo_tu, _cmo_fi)
_reg("PPO", _ppo_ft, _ppo_tl, _ppo_pt, _ppo_ta, _ppo_tu, _ppo_fi)
_reg("TRIX", _trix_ft, _trix_tl, _trix_pt, _trix_ta, _trix_tu, _trix_fi)
_reg("TSF", _tsf_ft, _tsf_tl, _tsf_pt, _tsf_ta, _tsf_tu, _tsf_fi)
_reg("ULTOSC", _ultosc_ft, _ultosc_tl, _ultosc_pt, _ultosc_ta, _ultosc_tu, _ultosc_fi)
_reg("BOP", _bop_ft, _bop_tl, _bop_pt, _bop_ta, _bop_tu, _bop_fi)
_reg("PLUS_DI", _plusdi_ft, _plusdi_tl, _plusdi_pt, _plusdi_ta, _plusdi_tu, _plusdi_fi)
_reg(
"MINUS_DI",
_minusdi_ft,
_minusdi_tl,
_minusdi_pt,
_minusdi_ta,
_minusdi_tu,
_minusdi_fi,
)
_reg("BBANDS", _bb_ft, _bb_tl, _bb_pt, _bb_ta, _bb_tu, _bb_fi)
_reg("ATR", _atr_ft, _atr_tl, _atr_pt, _atr_ta, _atr_tu, _atr_fi)
_reg("NATR", _natr_ft, _natr_tl, _natr_pt, _natr_ta, _natr_tu, _natr_fi)
_reg("TRANGE", _trange_ft, _trange_tl, _trange_pt, _trange_ta, _trange_tu, _trange_fi)
_reg("STDDEV", _stddev_ft, _stddev_tl, _stddev_pt, _stddev_ta, _stddev_tu, _stddev_fi)
_reg("VAR", _var_ft, _var_tl, _var_pt, _var_ta, _var_tu, _var_fi)
_reg("SAR", _sar_ft, _sar_tl, _sar_pt, _sar_ta, _sar_tu, _sar_fi)
_reg("KELTNER_CHANNELS", _kc_ft, _kc_tl, _kc_pt, _kc_ta, _kc_tu, _kc_fi)
_reg(
"DONCHIAN",
_donchian_ft,
_donchian_tl,
_donchian_pt,
_donchian_ta,
_donchian_tu,
_donchian_fi,
)
_reg(
"SUPERTREND",
_supertrend_ft,
_supertrend_tl,
_supertrend_pt,
_supertrend_ta,
_supertrend_tu,
_supertrend_fi,
)
_reg("CHOPPINESS_INDEX", _chop_ft, _chop_tl, _chop_pt, _chop_ta, _chop_tu, _chop_fi)
_reg("OBV", _obv_ft, _obv_tl, _obv_pt, _obv_ta, _obv_tu, _obv_fi)
_reg("AD", _ad_ft, _ad_tl, _ad_pt, _ad_ta, _ad_tu, _ad_fi)
_reg("ADOSC", _adosc_ft, _adosc_tl, _adosc_pt, _adosc_ta, _adosc_tu, _adosc_fi)
_reg("MFI", _mfi_ft, _mfi_tl, _mfi_pt, _mfi_ta, _mfi_tu, _mfi_fi)
_reg("VWAP", _vwap_ft, _vwap_tl, _vwap_pt, _vwap_ta, _vwap_tu, _vwap_fi)
_reg(
"AVGPRICE",
_avgprice_ft,
_avgprice_tl,
_avgprice_pt,
_avgprice_ta,
_avgprice_tu,
_avgprice_fi,
)
_reg(
"MEDPRICE",
_medprice_ft,
_medprice_tl,
_medprice_pt,
_medprice_ta,
_medprice_tu,
_medprice_fi,
)
_reg(
"TYPPRICE",
_typprice_ft,
_typprice_tl,
_typprice_pt,
_typprice_ta,
_typprice_tu,
_typprice_fi,
)
_reg(
"WCLPRICE",
_wclprice_ft,
_wclprice_tl,
_wclprice_pt,
_wclprice_ta,
_wclprice_tu,
_wclprice_fi,
)
_reg("SQRT", _sqrt_ft, _sqrt_tl, _sqrt_pt, _sqrt_ta, _sqrt_tu, _sqrt_fi)
_reg("LOG10", _log10_ft, _log10_tl, _log10_pt, _log10_ta, _log10_tu, _log10_fi)
_reg("ADD", _add_ft, _add_tl, _add_pt, _add_ta, _add_tu, _add_fi)
_reg(
"LINEARREG",
_linearreg_ft,
_linearreg_tl,
_linearreg_pt,
_linearreg_ta,
_linearreg_tu,
_linearreg_fi,
)
_reg(
"LINEARREG_SLOPE",
_linreg_slope_ft,
_linreg_slope_tl,
_linreg_slope_pt,
_linreg_slope_ta,
_linreg_slope_tu,
_linreg_slope_fi,
)
_reg("CORREL", _correl_ft, _correl_tl, _correl_pt, _correl_ta, _correl_tu, _correl_fi)
_reg("BETA", _beta_ft, _beta_tl, _beta_pt, _beta_ta, _beta_tu, _beta_fi)
_reg(
"HT_DCPERIOD",
_ht_dcperiod_ft,
_ht_dcperiod_tl,
_ht_dcperiod_pt,
_ht_dcperiod_ta,
_ht_dcperiod_tu,
_ht_dcperiod_fi,
)
_reg(
"HT_TRENDMODE",
_ht_trendmode_ft,
_ht_trendmode_tl,
_ht_trendmode_pt,
_ht_trendmode_ta,
_ht_trendmode_tu,
_ht_trendmode_fi,
)
_reg(
"CDLENGULFING",
_cdlengulfing_ft,
_cdlengulfing_tl,
_cdlengulfing_pt,
_cdlengulfing_ta,
_cdlengulfing_tu,
_cdlengulfing_fi,
)
_reg(
"CDLDOJI",
_cdldoji_ft,
_cdldoji_tl,
_cdldoji_pt,
_cdldoji_ta,
_cdldoji_tu,
_cdldoji_fi,
)
_reg(
"CDLHAMMER",
_cdlhammer_ft,
_cdlhammer_tl,
_cdlhammer_pt,
_cdlhammer_ta,
_cdlhammer_tu,
_cdlhammer_fi,
)
# ============================================================
# METADATA
# ============================================================
INDICATOR_DEFAULTS: dict[str, dict] = {
"SMA": {"timeperiod": 20},
"EMA": {"timeperiod": 20},
"WMA": {"timeperiod": 14},
"DEMA": {"timeperiod": 20},
"TEMA": {"timeperiod": 20},
"T3": {"timeperiod": 5},
"TRIMA": {"timeperiod": 20},
"KAMA": {"timeperiod": 10},
"HULL_MA": {"timeperiod": 16},
"VWMA": {"timeperiod": 20},
"MIDPOINT": {"timeperiod": 14},
"MIDPRICE": {"timeperiod": 14},
"RSI": {"timeperiod": 14},
"MACD": {"fastperiod": 12, "slowperiod": 26, "signalperiod": 9},
"STOCH": {"fastk_period": 14, "slowk_period": 3, "slowd_period": 3},
"CCI": {"timeperiod": 14},
"WILLR": {"timeperiod": 14},
"AROON": {"timeperiod": 14},
"AROONOSC": {"timeperiod": 14},
"ADX": {"timeperiod": 14},
"MOM": {"timeperiod": 10},
"ROC": {"timeperiod": 10},
"CMO": {"timeperiod": 14},
"PPO": {"fastperiod": 12, "slowperiod": 26},
"TRIX": {"timeperiod": 18},
"TSF": {"timeperiod": 14},
"ULTOSC": {"timeperiod1": 7, "timeperiod2": 14, "timeperiod3": 28},
"BOP": {},
"PLUS_DI": {"timeperiod": 14},
"MINUS_DI": {"timeperiod": 14},
"BBANDS": {"timeperiod": 20, "nbdevup": 2.0, "nbdevdn": 2.0},
"ATR": {"timeperiod": 14},
"NATR": {"timeperiod": 14},
"TRANGE": {},
"STDDEV": {"timeperiod": 20},
"VAR": {"timeperiod": 20},
"SAR": {"acceleration": 0.02, "maximum": 0.2},
"KELTNER_CHANNELS": {"timeperiod": 20},
"DONCHIAN": {"timeperiod": 20},
"SUPERTREND": {"timeperiod": 7},
"CHOPPINESS_INDEX": {"timeperiod": 14},
"OBV": {},
"AD": {},
"ADOSC": {"fastperiod": 3, "slowperiod": 10},
"MFI": {"timeperiod": 14},
"VWAP": {},
"AVGPRICE": {},
"MEDPRICE": {},
"TYPPRICE": {},
"WCLPRICE": {},
"SQRT": {},
"LOG10": {},
"ADD": {},
"LINEARREG": {"timeperiod": 14},
"LINEARREG_SLOPE": {"timeperiod": 14},
"CORREL": {"timeperiod": 30},
"BETA": {"timeperiod": 5},
"HT_DCPERIOD": {},
"HT_TRENDMODE": {},
"CDLENGULFING": {},
"CDLDOJI": {},
"CDLHAMMER": {},
}
INDICATOR_NAMES = list(INDICATOR_DEFAULTS.keys())
LIBRARY_NAMES = ["ferro_ta", "talib", "pandas_ta", "ta", "tulipy", "finta"]
INDICATOR_CATEGORIES: dict[str, list[str]] = {
"Overlap": [
"SMA",
"EMA",
"WMA",
"DEMA",
"TEMA",
"T3",
"TRIMA",
"KAMA",
"HULL_MA",
"VWMA",
"MIDPOINT",
"MIDPRICE",
],
"Momentum": [
"RSI",
"MACD",
"STOCH",
"CCI",
"WILLR",
"AROON",
"AROONOSC",
"ADX",
"MOM",
"ROC",
"CMO",
"PPO",
"TRIX",
"TSF",
"ULTOSC",
"BOP",
"PLUS_DI",
"MINUS_DI",
],
"Volatility": [
"BBANDS",
"ATR",
"NATR",
"TRANGE",
"STDDEV",
"VAR",
"SAR",
"KELTNER_CHANNELS",
"DONCHIAN",
"SUPERTREND",
"CHOPPINESS_INDEX",
],
"Volume": ["OBV", "AD", "ADOSC", "MFI", "VWAP"],
"Price Transform": ["AVGPRICE", "MEDPRICE", "TYPPRICE", "WCLPRICE"],
"Math": ["SQRT", "LOG10", "ADD"],
"Statistics": ["LINEARREG", "LINEARREG_SLOPE", "CORREL", "BETA"],
"Cycle": ["HT_DCPERIOD", "HT_TRENDMODE"],
"Pattern": ["CDLENGULFING", "CDLDOJI", "CDLHAMMER"],
}
# Cumulative: compare first-differences not absolute values
CUMULATIVE_INDICATORS = {"OBV", "AD", "ADOSC"}
# Binary output: use agreement rate not allclose
BINARY_INDICATORS = {"CDLENGULFING", "CDLDOJI", "CDLHAMMER", "HT_TRENDMODE"}
def execute_indicator(library, indicator, data, df=None, **kwargs):
"""Run indicator from library on data dict, return 1-D float64 array."""
if library not in available_libraries():
raise KeyError(f"Library not available in this environment: {library!r}")
key = (library, indicator)
if key not in REGISTRY:
raise KeyError(f"No wrapper for {key!r}")
if df is None:
from benchmarks.data_generator import get_pandas_ohlcv
df = get_pandas_ohlcv(data)
params = {**INDICATOR_DEFAULTS.get(indicator, {}), **kwargs}
return REGISTRY[key](data, df, **params)