2026-04-28 20:07:17 +10:00
|
|
|
"""
|
|
|
|
|
Priority 1 — Golden fixture tests.
|
|
|
|
|
|
|
|
|
|
Each test asserts two things for every column of every tracked indicator:
|
|
|
|
|
1. The last non-NaN value matches the stored golden value within a relative
|
|
|
|
|
tolerance of 1e-4 (0.01 %).
|
|
|
|
|
2. The number of non-NaN rows matches the stored count exactly.
|
|
|
|
|
|
|
|
|
|
To regenerate fixtures after an intentional algorithm change run:
|
|
|
|
|
python -m tests.fixtures.generate_fixtures
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
import json
|
|
|
|
|
import math
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
from unittest import TestCase
|
|
|
|
|
|
|
|
|
|
import pandas as pd
|
|
|
|
|
|
|
|
|
|
import pandas_ta_classic as ta
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
# Load fixtures & sample data
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
_FIXTURE_PATH = Path(__file__).parent / "fixtures" / "expected_values.json"
|
|
|
|
|
with open(_FIXTURE_PATH) as _fh:
|
|
|
|
|
_FIXTURES: dict[str, dict] = json.load(_fh)
|
|
|
|
|
|
|
|
|
|
_DATA_PATH = Path(__file__).parent.parent / "examples" / "data" / "SPY_D.csv"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _load_data() -> pd.DataFrame:
|
|
|
|
|
df = pd.read_csv(_DATA_PATH, index_col="date", parse_dates=True)
|
|
|
|
|
df.drop(columns=["Unnamed: 0"], inplace=True, errors="ignore")
|
|
|
|
|
df.columns = df.columns.str.lower()
|
|
|
|
|
return df
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
# Helper — recompute every indicator from the same definitions used in
|
|
|
|
|
# generate_fixtures.py so the two files stay in sync.
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _compute_all(df: pd.DataFrame) -> dict[str, object]:
|
2026-07-04 18:19:45 +10:00
|
|
|
o, h, low, c, v = df["open"], df["high"], df["low"], df["close"], df["volume"]
|
2026-04-28 20:07:17 +10:00
|
|
|
_ema_fast = ta.ema(c, length=8, talib=False)
|
|
|
|
|
_ema_slow = ta.ema(c, length=21, talib=False)
|
|
|
|
|
_trend_bool = _ema_fast > _ema_slow
|
|
|
|
|
_rsi_14_sig = ta.rsi(c, length=14, talib=False)
|
|
|
|
|
return {
|
|
|
|
|
# ---- Overlap (TA-Lib backed) ----
|
|
|
|
|
"sma_20": ta.sma(c, length=20),
|
|
|
|
|
"ema_20": ta.ema(c, length=20, talib=False),
|
|
|
|
|
"dema_10": ta.dema(c, length=10, talib=False),
|
|
|
|
|
"tema_10": ta.tema(c, length=10, talib=False),
|
|
|
|
|
"wma_10": ta.wma(c, length=10, talib=False),
|
|
|
|
|
"midpoint_14": ta.midpoint(c, 14, talib=False),
|
2026-07-04 18:19:45 +10:00
|
|
|
"midprice_14": ta.midprice(h, low, 14, talib=False),
|
2026-04-28 20:07:17 +10:00
|
|
|
"t3_10": ta.t3(c, 10, talib=False),
|
2026-07-04 18:19:45 +10:00
|
|
|
"wcp": ta.wcp(h, low, c, talib=False),
|
|
|
|
|
"hl2": ta.hl2(h, low),
|
|
|
|
|
"hlc3": ta.hlc3(h, low, c, talib=False),
|
|
|
|
|
"ohlc4": ta.ohlc4(o, h, low, c),
|
2026-04-28 20:07:17 +10:00
|
|
|
# ---- Overlap (native) ----
|
|
|
|
|
"hma_10": ta.hma(c, length=10),
|
|
|
|
|
"alma_10": ta.alma(c, length=10),
|
|
|
|
|
"trima_10": ta.trima(c, length=10, talib=False),
|
|
|
|
|
"fwma_10": ta.fwma(c, length=10),
|
2026-07-04 18:19:45 +10:00
|
|
|
"hilo": ta.hilo(h, low, c),
|
2026-04-28 20:07:17 +10:00
|
|
|
"hwma": ta.hwma(c),
|
|
|
|
|
"jma": ta.jma(c),
|
|
|
|
|
"kama": ta.kama(c),
|
|
|
|
|
"linreg_14": ta.linreg(c, length=14),
|
|
|
|
|
"mama": ta.mama(c),
|
|
|
|
|
"mcgd": ta.mcgd(c),
|
|
|
|
|
"mmar": ta.mmar(c),
|
|
|
|
|
"pwma_10": ta.pwma(c, length=10),
|
|
|
|
|
"rainbow": ta.rainbow(c),
|
|
|
|
|
"rma": ta.rma(c),
|
|
|
|
|
"sinwma_14": ta.sinwma(c, length=14),
|
|
|
|
|
"ssf_10": ta.ssf(c, length=10),
|
2026-07-04 18:19:45 +10:00
|
|
|
"supertrend": ta.supertrend(h, low, c),
|
2026-04-28 20:07:17 +10:00
|
|
|
"swma": ta.swma(c),
|
|
|
|
|
"tsf_14": ta.tsf(c, length=14),
|
|
|
|
|
"vidya": ta.vidya(c),
|
2026-07-04 18:19:45 +10:00
|
|
|
"vwap": ta.vwap(h, low, c, v),
|
2026-04-28 20:07:17 +10:00
|
|
|
"vwma_10": ta.vwma(c, v, length=10),
|
|
|
|
|
"zlma_10": ta.zlma(c, length=10),
|
|
|
|
|
# ---- Momentum (TA-Lib backed) ----
|
|
|
|
|
"rsi_14": ta.rsi(c, length=14, talib=False),
|
|
|
|
|
"macd_12_26_9": ta.macd(c, fast=12, slow=26, signal=9, talib=False),
|
2026-07-04 18:19:45 +10:00
|
|
|
"stoch": ta.stoch(h, low, c, talib=False),
|
|
|
|
|
"cci_14": ta.cci(h, low, c, length=14, talib=False),
|
2026-04-28 20:07:17 +10:00
|
|
|
"roc_10": ta.roc(c, length=10, talib=False),
|
2026-07-04 18:19:45 +10:00
|
|
|
"willr_14": ta.willr(h, low, c, length=14, talib=False),
|
2026-04-28 20:07:17 +10:00
|
|
|
"apo": ta.apo(c, 12, 26, talib=False),
|
2026-07-04 18:19:45 +10:00
|
|
|
"bop": ta.bop(o, h, low, c, talib=False),
|
2026-04-28 20:07:17 +10:00
|
|
|
"mom_10": ta.mom(c, length=10, talib=False),
|
2026-07-04 18:19:45 +10:00
|
|
|
"uo": ta.uo(h, low, c, talib=False),
|
2026-04-28 20:07:17 +10:00
|
|
|
# ---- Momentum (native) ----
|
2026-07-04 18:19:45 +10:00
|
|
|
"ao": ta.ao(h, low),
|
2026-04-28 20:07:17 +10:00
|
|
|
"bias_10": ta.bias(c, length=10),
|
2026-07-04 18:19:45 +10:00
|
|
|
"brar": ta.brar(o, h, low, c),
|
2026-04-28 20:07:17 +10:00
|
|
|
"cfo_10": ta.cfo(c, length=10),
|
|
|
|
|
"cg": ta.cg(c),
|
|
|
|
|
"cmo_14": ta.cmo(c, length=14, talib=False),
|
|
|
|
|
"coppock": ta.coppock(c),
|
|
|
|
|
"cti": ta.cti(c),
|
2026-07-04 18:19:45 +10:00
|
|
|
"dm_14": ta.dm(h, low, length=14, talib=False),
|
2026-04-28 20:07:17 +10:00
|
|
|
"er": ta.er(c),
|
2026-07-04 18:19:45 +10:00
|
|
|
"eri": ta.eri(h, low, c),
|
|
|
|
|
"fisher": ta.fisher(h, low),
|
|
|
|
|
"inertia": ta.inertia(c, h, low),
|
|
|
|
|
"kdj": ta.kdj(h, low, c),
|
2026-04-28 20:07:17 +10:00
|
|
|
"kst": ta.kst(c),
|
|
|
|
|
"lrsi": ta.lrsi(c),
|
2026-07-04 18:19:45 +10:00
|
|
|
"pgo_14": ta.pgo(h, low, c, length=14),
|
2026-04-28 20:07:17 +10:00
|
|
|
"po": ta.po(c),
|
|
|
|
|
"ppo": ta.ppo(c),
|
|
|
|
|
"psl": ta.psl(c, o),
|
|
|
|
|
"pvo": ta.pvo(v),
|
|
|
|
|
"qqe": ta.qqe(c),
|
|
|
|
|
"rsx": ta.rsx(c),
|
2026-07-04 18:19:45 +10:00
|
|
|
"rvgi": ta.rvgi(o, h, low, c),
|
2026-04-28 20:07:17 +10:00
|
|
|
"slope": ta.slope(c),
|
|
|
|
|
"smi": ta.smi(c),
|
2026-07-04 18:19:45 +10:00
|
|
|
"squeeze": ta.squeeze(h, low, c),
|
|
|
|
|
"squeeze_pro": ta.squeeze_pro(h, low, c),
|
2026-04-28 20:07:17 +10:00
|
|
|
"stc": ta.stc(c),
|
|
|
|
|
"stochrsi": ta.stochrsi(c),
|
|
|
|
|
"td_seq": ta.td_seq(c),
|
|
|
|
|
"trix": ta.trix(c),
|
|
|
|
|
"trixh": ta.trixh(c),
|
|
|
|
|
"tsi": ta.tsi(c),
|
|
|
|
|
"vwmacd": ta.vwmacd(c, v),
|
|
|
|
|
# ---- Volatility (TA-Lib backed) ----
|
2026-07-04 18:19:45 +10:00
|
|
|
"atr_14": ta.atr(h, low, c, length=14, talib=False),
|
2026-04-28 20:07:17 +10:00
|
|
|
"bbands_20": ta.bbands(c, length=20, talib=False),
|
2026-07-04 18:19:45 +10:00
|
|
|
"natr_14": ta.natr(h, low, c, length=14, talib=False),
|
|
|
|
|
"true_range": ta.true_range(h, low, c, talib=False),
|
2026-04-28 20:07:17 +10:00
|
|
|
# ---- Volatility (native) ----
|
2026-07-04 18:19:45 +10:00
|
|
|
"donchian_20": ta.donchian(h, low, lower_length=20, upper_length=20),
|
|
|
|
|
"kc_20": ta.kc(h, low, c, length=20),
|
|
|
|
|
"aberration": ta.aberration(h, low, c),
|
|
|
|
|
"accbands": ta.accbands(h, low, c),
|
|
|
|
|
"ce": ta.ce(h, low, c),
|
2026-04-28 20:07:17 +10:00
|
|
|
"hwc": ta.hwc(c),
|
2026-07-04 18:19:45 +10:00
|
|
|
"massi": ta.massi(h, low),
|
|
|
|
|
"pdist": ta.pdist(o, h, low, c),
|
|
|
|
|
"rvi_vol": ta.rvi(c, h, low),
|
|
|
|
|
"thermo": ta.thermo(h, low),
|
2026-04-28 20:07:17 +10:00
|
|
|
"ui": ta.ui(c),
|
|
|
|
|
# ---- Trend (TA-Lib backed) ----
|
2026-07-04 18:19:45 +10:00
|
|
|
"adx_14": ta.adx(h, low, c, length=14, talib=False),
|
|
|
|
|
"aroon_14": ta.aroon(h, low, length=14, talib=False),
|
2026-04-28 20:07:17 +10:00
|
|
|
# ---- Trend (native) ----
|
2026-07-04 18:19:45 +10:00
|
|
|
"psar": ta.psar(h, low, c),
|
2026-04-28 20:07:17 +10:00
|
|
|
"decreasing": ta.decreasing(c),
|
|
|
|
|
"increasing": ta.increasing(c),
|
2026-07-04 18:19:45 +10:00
|
|
|
"adxr": ta.adxr(h, low, c, length=14, talib=False),
|
2026-04-28 20:07:17 +10:00
|
|
|
"amat": ta.amat(c, fast=8, slow=21),
|
2026-07-04 18:19:45 +10:00
|
|
|
"chop": ta.chop(h, low, c),
|
|
|
|
|
"cksp": ta.cksp(h, low, c),
|
|
|
|
|
"cpr": ta.cpr(o, h, low, c),
|
2026-04-28 20:07:17 +10:00
|
|
|
"decay": ta.decay(c),
|
|
|
|
|
"dpo_14": ta.dpo(c, length=14),
|
|
|
|
|
"long_run": ta.long_run(_ema_fast, _ema_slow),
|
2026-07-04 18:19:45 +10:00
|
|
|
"pmax": ta.pmax(h, low, c),
|
2026-04-28 20:07:17 +10:00
|
|
|
"qstick": ta.qstick(o, c),
|
|
|
|
|
"short_run": ta.short_run(_ema_fast, _ema_slow),
|
2026-07-04 18:19:45 +10:00
|
|
|
"ttm_trend": ta.ttm_trend(h, low, c),
|
2026-04-28 20:07:17 +10:00
|
|
|
"vhf": ta.vhf(c),
|
2026-07-04 18:19:45 +10:00
|
|
|
"vortex": ta.vortex(h, low, c),
|
2026-04-28 20:07:17 +10:00
|
|
|
# ---- Volume (TA-Lib backed) ----
|
|
|
|
|
"obv": ta.obv(c, v, talib=False),
|
2026-07-04 18:19:45 +10:00
|
|
|
"mfi_14": ta.mfi(h, low, c, v, length=14, talib=False),
|
|
|
|
|
"ad": ta.ad(h, low, c, v, talib=False),
|
|
|
|
|
"adosc": ta.adosc(h, low, c, v, talib=False),
|
2026-04-28 20:07:17 +10:00
|
|
|
# ---- Volume (native) ----
|
2026-07-04 18:19:45 +10:00
|
|
|
"cmf_20": ta.cmf(h, low, c, v, length=20),
|
2026-04-28 20:07:17 +10:00
|
|
|
"aobv": ta.aobv(c, v),
|
|
|
|
|
"efi": ta.efi(c, v),
|
2026-07-04 18:19:45 +10:00
|
|
|
"eom": ta.eom(h, low, c, v),
|
|
|
|
|
"kvo": ta.kvo(h, low, c, v),
|
2026-04-28 20:07:17 +10:00
|
|
|
"nvi": ta.nvi(c, v),
|
|
|
|
|
"pvi": ta.pvi(c, v),
|
|
|
|
|
"pvol": ta.pvol(c, v),
|
|
|
|
|
"pvr": ta.pvr(c, v),
|
|
|
|
|
"pvt": ta.pvt(c, v),
|
|
|
|
|
"vfi": ta.vfi(c, v),
|
|
|
|
|
# ---- Statistics (TA-Lib backed) ----
|
|
|
|
|
"stdev_20": ta.stdev(c, length=20, talib=False),
|
|
|
|
|
"variance_20": ta.variance(c, length=20, talib=False),
|
|
|
|
|
# ---- Statistics (native) ----
|
|
|
|
|
"zscore_20": ta.zscore(c, length=20),
|
|
|
|
|
"kurtosis_20": ta.kurtosis(c, length=20),
|
|
|
|
|
"skew_20": ta.skew(c, length=20),
|
|
|
|
|
"beta": ta.beta(c, o),
|
|
|
|
|
"correl": ta.correl(c, o),
|
|
|
|
|
"entropy_10": ta.entropy(c, length=10),
|
|
|
|
|
"mad_10": ta.mad(c, length=10),
|
|
|
|
|
"median_14": ta.median(c, length=14),
|
|
|
|
|
"quantile_14": ta.quantile(c, length=14),
|
|
|
|
|
"tos_stdevall": ta.tos_stdevall(c, length=30),
|
|
|
|
|
# ---- Cycles (TA-Lib backed) ----
|
|
|
|
|
"ht_dcperiod": ta.ht_dcperiod(c),
|
|
|
|
|
"ht_dcphase": ta.ht_dcphase(c),
|
|
|
|
|
"ht_phasor": ta.ht_phasor(c),
|
|
|
|
|
"ht_sine": ta.ht_sine(c),
|
|
|
|
|
"ht_trendmode": ta.ht_trendmode(c),
|
|
|
|
|
"ht_trendline": ta.ht_trendline(c),
|
|
|
|
|
# ---- Cycles (native) ----
|
|
|
|
|
"dsp": ta.dsp(c),
|
|
|
|
|
"ebsw": ta.ebsw(c),
|
|
|
|
|
# ---- Performance ----
|
|
|
|
|
"log_return": ta.log_return(c),
|
|
|
|
|
"percent_return": ta.percent_return(c),
|
|
|
|
|
"drawdown": ta.drawdown(c),
|
|
|
|
|
# ---- Candles ----
|
2026-07-04 18:19:45 +10:00
|
|
|
"ha": ta.ha(o, h, low, c),
|
|
|
|
|
"cdl_doji": ta.cdl_doji(o, h, low, c),
|
|
|
|
|
"cdl_inside": ta.cdl_inside(o, h, low, c),
|
|
|
|
|
"cdl_z": ta.cdl_z(o, h, low, c),
|
2026-04-28 20:07:17 +10:00
|
|
|
# ---- Overlap (additional) ----
|
2026-07-04 18:19:45 +10:00
|
|
|
"ichimoku": ta.ichimoku(h, low, c)[0],
|
2026-04-28 20:07:17 +10:00
|
|
|
"ma_ema_20": ta.ma("ema", c, length=20),
|
|
|
|
|
# ---- Trend (additional) ----
|
|
|
|
|
"tsignals": ta.tsignals(_trend_bool),
|
|
|
|
|
"xsignals": ta.xsignals(_rsi_14_sig, 70, 30),
|
|
|
|
|
# ---- Volume (additional) ----
|
|
|
|
|
"vp": ta.vp(c, v),
|
|
|
|
|
# ---- Candles — CDL patterns (via dispatcher) ----
|
2026-07-04 18:19:45 +10:00
|
|
|
"cdl_pattern": ta.cdl_pattern(o, h, low, c),
|
|
|
|
|
"cdl_2crows": ta.cdl_pattern(o, h, low, c, name="2crows"),
|
|
|
|
|
"cdl_3blackcrows": ta.cdl_pattern(o, h, low, c, name="3blackcrows"),
|
|
|
|
|
"cdl_3inside": ta.cdl_pattern(o, h, low, c, name="3inside"),
|
|
|
|
|
"cdl_3linestrike": ta.cdl_pattern(o, h, low, c, name="3linestrike"),
|
|
|
|
|
"cdl_3outside": ta.cdl_pattern(o, h, low, c, name="3outside"),
|
|
|
|
|
"cdl_3starsinsouth": ta.cdl_pattern(o, h, low, c, name="3starsinsouth"),
|
|
|
|
|
"cdl_3whitesoldiers": ta.cdl_pattern(o, h, low, c, name="3whitesoldiers"),
|
|
|
|
|
"cdl_abandonedbaby": ta.cdl_pattern(o, h, low, c, name="abandonedbaby"),
|
|
|
|
|
"cdl_advanceblock": ta.cdl_pattern(o, h, low, c, name="advanceblock"),
|
|
|
|
|
"cdl_belthold": ta.cdl_pattern(o, h, low, c, name="belthold"),
|
|
|
|
|
"cdl_breakaway": ta.cdl_pattern(o, h, low, c, name="breakaway"),
|
|
|
|
|
"cdl_closingmarubozu": ta.cdl_pattern(o, h, low, c, name="closingmarubozu"),
|
|
|
|
|
"cdl_concealbabyswall": ta.cdl_pattern(o, h, low, c, name="concealbabyswall"),
|
|
|
|
|
"cdl_counterattack": ta.cdl_pattern(o, h, low, c, name="counterattack"),
|
|
|
|
|
"cdl_darkcloudcover": ta.cdl_pattern(o, h, low, c, name="darkcloudcover"),
|
|
|
|
|
"cdl_dojistar": ta.cdl_pattern(o, h, low, c, name="dojistar"),
|
|
|
|
|
"cdl_dragonflydoji": ta.cdl_pattern(o, h, low, c, name="dragonflydoji"),
|
|
|
|
|
"cdl_engulfing": ta.cdl_pattern(o, h, low, c, name="engulfing"),
|
|
|
|
|
"cdl_eveningdojistar": ta.cdl_pattern(o, h, low, c, name="eveningdojistar"),
|
|
|
|
|
"cdl_eveningstar": ta.cdl_pattern(o, h, low, c, name="eveningstar"),
|
|
|
|
|
"cdl_gapsidesidewhite": ta.cdl_pattern(o, h, low, c, name="gapsidesidewhite"),
|
|
|
|
|
"cdl_gravestonedoji": ta.cdl_pattern(o, h, low, c, name="gravestonedoji"),
|
|
|
|
|
"cdl_hammer": ta.cdl_pattern(o, h, low, c, name="hammer"),
|
|
|
|
|
"cdl_hangingman": ta.cdl_pattern(o, h, low, c, name="hangingman"),
|
|
|
|
|
"cdl_harami": ta.cdl_pattern(o, h, low, c, name="harami"),
|
|
|
|
|
"cdl_haramicross": ta.cdl_pattern(o, h, low, c, name="haramicross"),
|
|
|
|
|
"cdl_highwave": ta.cdl_pattern(o, h, low, c, name="highwave"),
|
|
|
|
|
"cdl_hikkake": ta.cdl_pattern(o, h, low, c, name="hikkake"),
|
|
|
|
|
"cdl_hikkakemod": ta.cdl_pattern(o, h, low, c, name="hikkakemod"),
|
|
|
|
|
"cdl_homingpigeon": ta.cdl_pattern(o, h, low, c, name="homingpigeon"),
|
|
|
|
|
"cdl_identical3crows": ta.cdl_pattern(o, h, low, c, name="identical3crows"),
|
|
|
|
|
"cdl_inneck": ta.cdl_pattern(o, h, low, c, name="inneck"),
|
|
|
|
|
"cdl_invertedhammer": ta.cdl_pattern(o, h, low, c, name="invertedhammer"),
|
|
|
|
|
"cdl_kicking": ta.cdl_pattern(o, h, low, c, name="kicking"),
|
|
|
|
|
"cdl_kickingbylength": ta.cdl_pattern(o, h, low, c, name="kickingbylength"),
|
|
|
|
|
"cdl_ladderbottom": ta.cdl_pattern(o, h, low, c, name="ladderbottom"),
|
|
|
|
|
"cdl_longleggeddoji": ta.cdl_pattern(o, h, low, c, name="longleggeddoji"),
|
|
|
|
|
"cdl_longline": ta.cdl_pattern(o, h, low, c, name="longline"),
|
|
|
|
|
"cdl_marubozu": ta.cdl_pattern(o, h, low, c, name="marubozu"),
|
|
|
|
|
"cdl_matchinglow": ta.cdl_pattern(o, h, low, c, name="matchinglow"),
|
|
|
|
|
"cdl_mathold": ta.cdl_pattern(o, h, low, c, name="mathold"),
|
|
|
|
|
"cdl_morningdojistar": ta.cdl_pattern(o, h, low, c, name="morningdojistar"),
|
|
|
|
|
"cdl_morningstar": ta.cdl_pattern(o, h, low, c, name="morningstar"),
|
|
|
|
|
"cdl_onneck": ta.cdl_pattern(o, h, low, c, name="onneck"),
|
|
|
|
|
"cdl_piercing": ta.cdl_pattern(o, h, low, c, name="piercing"),
|
|
|
|
|
"cdl_rickshawman": ta.cdl_pattern(o, h, low, c, name="rickshawman"),
|
|
|
|
|
"cdl_risefall3methods": ta.cdl_pattern(o, h, low, c, name="risefall3methods"),
|
|
|
|
|
"cdl_separatinglines": ta.cdl_pattern(o, h, low, c, name="separatinglines"),
|
|
|
|
|
"cdl_shootingstar": ta.cdl_pattern(o, h, low, c, name="shootingstar"),
|
|
|
|
|
"cdl_shortline": ta.cdl_pattern(o, h, low, c, name="shortline"),
|
|
|
|
|
"cdl_spinningtop": ta.cdl_pattern(o, h, low, c, name="spinningtop"),
|
|
|
|
|
"cdl_stalledpattern": ta.cdl_pattern(o, h, low, c, name="stalledpattern"),
|
|
|
|
|
"cdl_sticksandwich": ta.cdl_pattern(o, h, low, c, name="sticksandwich"),
|
|
|
|
|
"cdl_takuri": ta.cdl_pattern(o, h, low, c, name="takuri"),
|
|
|
|
|
"cdl_tasukigap": ta.cdl_pattern(o, h, low, c, name="tasukigap"),
|
|
|
|
|
"cdl_thrusting": ta.cdl_pattern(o, h, low, c, name="thrusting"),
|
|
|
|
|
"cdl_tristar": ta.cdl_pattern(o, h, low, c, name="tristar"),
|
|
|
|
|
"cdl_unique3river": ta.cdl_pattern(o, h, low, c, name="unique3river"),
|
|
|
|
|
"cdl_upsidegap2crows": ta.cdl_pattern(o, h, low, c, name="upsidegap2crows"),
|
|
|
|
|
"cdl_xsidegap3methods": ta.cdl_pattern(o, h, low, c, name="xsidegap3methods"),
|
2026-04-28 20:07:17 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
# Tolerance
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
REL_TOL = 1e-4 # 0.01 % relative tolerance for floating-point comparisons
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _approx_equal(actual: float, expected: float) -> bool:
|
|
|
|
|
"""Return True when |actual - expected| / |expected| <= REL_TOL."""
|
|
|
|
|
if expected == 0.0:
|
|
|
|
|
return abs(actual) <= REL_TOL
|
|
|
|
|
return abs(actual - expected) / abs(expected) <= REL_TOL
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
# Test class
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestIndicatorValues(TestCase):
|
|
|
|
|
"""Assert that every tracked indicator produces the expected golden values."""
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def setUpClass(cls):
|
|
|
|
|
cls.df = _load_data()
|
|
|
|
|
cls.results = _compute_all(cls.df)
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def tearDownClass(cls):
|
|
|
|
|
del cls.df
|
|
|
|
|
del cls.results
|
|
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------
|
|
|
|
|
# Internal helper used by every generated test method
|
|
|
|
|
# ------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
def _check_fixture(self, fixture_key: str) -> None:
|
|
|
|
|
"""Assert last value and non-NaN count for every column of fixture_key."""
|
2026-06-27 17:33:32 +02:00
|
|
|
import unittest
|
|
|
|
|
|
|
|
|
|
if fixture_key not in _FIXTURES:
|
|
|
|
|
raise unittest.SkipTest(
|
2026-06-28 17:30:41 +10:00
|
|
|
f"Fixture {fixture_key!r} not present in expected_values.json " f"(may require an optional dependency such as tulipy)"
|
2026-06-27 17:33:32 +02:00
|
|
|
)
|
2026-06-24 22:39:09 +10:00
|
|
|
self.assertIn(fixture_key, self.results, f"No result computed for {fixture_key!r}")
|
2026-04-28 20:07:17 +10:00
|
|
|
result = self.results[fixture_key]
|
|
|
|
|
if result is None:
|
|
|
|
|
self.fail(f"{fixture_key!r} returned None")
|
|
|
|
|
|
|
|
|
|
# Normalise to DataFrame so we iterate columns uniformly
|
|
|
|
|
if isinstance(result, pd.Series):
|
|
|
|
|
result = result.to_frame(name=result.name)
|
|
|
|
|
|
|
|
|
|
expected_fixture = _FIXTURES[fixture_key]
|
|
|
|
|
|
|
|
|
|
for col, expected in expected_fixture.items():
|
|
|
|
|
with self.subTest(col=col):
|
|
|
|
|
self.assertIn(
|
|
|
|
|
col,
|
|
|
|
|
result.columns,
|
|
|
|
|
f"Column {col!r} missing from {fixture_key!r} result",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
series = result[col]
|
|
|
|
|
actual_non_nan = int(series.notna().sum())
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
actual_non_nan,
|
|
|
|
|
expected["non_nan_count"],
|
2026-06-24 22:39:09 +10:00
|
|
|
f"{fixture_key!r}[{col!r}]: non_nan_count " f"{actual_non_nan} != {expected['non_nan_count']}",
|
2026-04-28 20:07:17 +10:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
expected_last = expected["last_value"]
|
|
|
|
|
if expected_last is None:
|
|
|
|
|
return # column was all-NaN when fixtures were generated
|
|
|
|
|
|
|
|
|
|
clean = series.dropna()
|
|
|
|
|
self.assertFalse(
|
|
|
|
|
clean.empty,
|
|
|
|
|
f"{fixture_key!r}[{col!r}]: result is all-NaN but fixture has a value",
|
|
|
|
|
)
|
|
|
|
|
actual_last = float(clean.iloc[-1])
|
|
|
|
|
self.assertFalse(
|
|
|
|
|
math.isnan(actual_last) or math.isinf(actual_last),
|
|
|
|
|
f"{fixture_key!r}[{col!r}]: last value is NaN/Inf",
|
|
|
|
|
)
|
|
|
|
|
self.assertTrue(
|
|
|
|
|
_approx_equal(actual_last, expected_last),
|
2026-06-24 22:39:09 +10:00
|
|
|
f"{fixture_key!r}[{col!r}]: last value {actual_last:.8f} " f"differs from golden {expected_last:.8f}",
|
2026-04-28 20:07:17 +10:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------
|
|
|
|
|
# One test method per fixture key
|
|
|
|
|
# ------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
# Overlap — TA-Lib backed
|
|
|
|
|
def test_sma_20(self):
|
|
|
|
|
self._check_fixture("sma_20")
|
|
|
|
|
|
|
|
|
|
def test_ema_20(self):
|
|
|
|
|
self._check_fixture("ema_20")
|
|
|
|
|
|
|
|
|
|
def test_dema_10(self):
|
|
|
|
|
self._check_fixture("dema_10")
|
|
|
|
|
|
|
|
|
|
def test_tema_10(self):
|
|
|
|
|
self._check_fixture("tema_10")
|
|
|
|
|
|
|
|
|
|
def test_wma_10(self):
|
|
|
|
|
self._check_fixture("wma_10")
|
|
|
|
|
|
|
|
|
|
def test_midpoint_14(self):
|
|
|
|
|
self._check_fixture("midpoint_14")
|
|
|
|
|
|
|
|
|
|
def test_midprice_14(self):
|
|
|
|
|
self._check_fixture("midprice_14")
|
|
|
|
|
|
|
|
|
|
def test_t3_10(self):
|
|
|
|
|
self._check_fixture("t3_10")
|
|
|
|
|
|
|
|
|
|
def test_wcp(self):
|
|
|
|
|
self._check_fixture("wcp")
|
|
|
|
|
|
|
|
|
|
def test_hl2(self):
|
|
|
|
|
self._check_fixture("hl2")
|
|
|
|
|
|
|
|
|
|
def test_hlc3(self):
|
|
|
|
|
self._check_fixture("hlc3")
|
|
|
|
|
|
|
|
|
|
def test_ohlc4(self):
|
|
|
|
|
self._check_fixture("ohlc4")
|
|
|
|
|
|
|
|
|
|
# Overlap — native
|
|
|
|
|
def test_hma_10(self):
|
|
|
|
|
self._check_fixture("hma_10")
|
|
|
|
|
|
|
|
|
|
def test_alma_10(self):
|
|
|
|
|
self._check_fixture("alma_10")
|
|
|
|
|
|
|
|
|
|
def test_trima_10(self):
|
|
|
|
|
self._check_fixture("trima_10")
|
|
|
|
|
|
|
|
|
|
def test_fwma_10(self):
|
|
|
|
|
self._check_fixture("fwma_10")
|
|
|
|
|
|
|
|
|
|
def test_hilo(self):
|
|
|
|
|
self._check_fixture("hilo")
|
|
|
|
|
|
|
|
|
|
def test_hwma(self):
|
|
|
|
|
self._check_fixture("hwma")
|
|
|
|
|
|
|
|
|
|
def test_jma(self):
|
|
|
|
|
self._check_fixture("jma")
|
|
|
|
|
|
|
|
|
|
def test_kama(self):
|
|
|
|
|
self._check_fixture("kama")
|
|
|
|
|
|
|
|
|
|
def test_linreg_14(self):
|
|
|
|
|
self._check_fixture("linreg_14")
|
|
|
|
|
|
|
|
|
|
def test_mama(self):
|
|
|
|
|
self._check_fixture("mama")
|
|
|
|
|
|
|
|
|
|
def test_mcgd(self):
|
|
|
|
|
self._check_fixture("mcgd")
|
|
|
|
|
|
|
|
|
|
def test_mmar(self):
|
|
|
|
|
self._check_fixture("mmar")
|
|
|
|
|
|
|
|
|
|
def test_pwma_10(self):
|
|
|
|
|
self._check_fixture("pwma_10")
|
|
|
|
|
|
|
|
|
|
def test_rainbow(self):
|
|
|
|
|
self._check_fixture("rainbow")
|
|
|
|
|
|
|
|
|
|
def test_rma(self):
|
|
|
|
|
self._check_fixture("rma")
|
|
|
|
|
|
|
|
|
|
def test_sinwma_14(self):
|
|
|
|
|
self._check_fixture("sinwma_14")
|
|
|
|
|
|
|
|
|
|
def test_ssf_10(self):
|
|
|
|
|
self._check_fixture("ssf_10")
|
|
|
|
|
|
|
|
|
|
def test_supertrend(self):
|
|
|
|
|
self._check_fixture("supertrend")
|
|
|
|
|
|
|
|
|
|
def test_swma(self):
|
|
|
|
|
self._check_fixture("swma")
|
|
|
|
|
|
|
|
|
|
def test_tsf_14(self):
|
|
|
|
|
self._check_fixture("tsf_14")
|
|
|
|
|
|
|
|
|
|
def test_vidya(self):
|
|
|
|
|
self._check_fixture("vidya")
|
|
|
|
|
|
|
|
|
|
def test_vwap(self):
|
|
|
|
|
self._check_fixture("vwap")
|
|
|
|
|
|
|
|
|
|
def test_vwma_10(self):
|
|
|
|
|
self._check_fixture("vwma_10")
|
|
|
|
|
|
|
|
|
|
def test_zlma_10(self):
|
|
|
|
|
self._check_fixture("zlma_10")
|
|
|
|
|
|
|
|
|
|
# Momentum — TA-Lib backed
|
|
|
|
|
def test_rsi_14(self):
|
|
|
|
|
self._check_fixture("rsi_14")
|
|
|
|
|
|
|
|
|
|
def test_macd_12_26_9(self):
|
|
|
|
|
self._check_fixture("macd_12_26_9")
|
|
|
|
|
|
|
|
|
|
def test_stoch(self):
|
|
|
|
|
self._check_fixture("stoch")
|
|
|
|
|
|
|
|
|
|
def test_cci_14(self):
|
|
|
|
|
self._check_fixture("cci_14")
|
|
|
|
|
|
|
|
|
|
def test_roc_10(self):
|
|
|
|
|
self._check_fixture("roc_10")
|
|
|
|
|
|
|
|
|
|
def test_willr_14(self):
|
|
|
|
|
self._check_fixture("willr_14")
|
|
|
|
|
|
|
|
|
|
def test_apo(self):
|
|
|
|
|
self._check_fixture("apo")
|
|
|
|
|
|
|
|
|
|
def test_bop(self):
|
|
|
|
|
self._check_fixture("bop")
|
|
|
|
|
|
|
|
|
|
def test_mom_10(self):
|
|
|
|
|
self._check_fixture("mom_10")
|
|
|
|
|
|
|
|
|
|
def test_uo(self):
|
|
|
|
|
self._check_fixture("uo")
|
|
|
|
|
|
|
|
|
|
# Momentum — native
|
|
|
|
|
def test_ao(self):
|
|
|
|
|
self._check_fixture("ao")
|
|
|
|
|
|
|
|
|
|
def test_bias_10(self):
|
|
|
|
|
self._check_fixture("bias_10")
|
|
|
|
|
|
|
|
|
|
def test_brar(self):
|
|
|
|
|
self._check_fixture("brar")
|
|
|
|
|
|
|
|
|
|
def test_cfo_10(self):
|
|
|
|
|
self._check_fixture("cfo_10")
|
|
|
|
|
|
|
|
|
|
def test_cg(self):
|
|
|
|
|
self._check_fixture("cg")
|
|
|
|
|
|
|
|
|
|
def test_cmo_14(self):
|
|
|
|
|
self._check_fixture("cmo_14")
|
|
|
|
|
|
|
|
|
|
def test_coppock(self):
|
|
|
|
|
self._check_fixture("coppock")
|
|
|
|
|
|
|
|
|
|
def test_cti(self):
|
|
|
|
|
self._check_fixture("cti")
|
|
|
|
|
|
|
|
|
|
def test_dm_14(self):
|
|
|
|
|
self._check_fixture("dm_14")
|
|
|
|
|
|
|
|
|
|
def test_er(self):
|
|
|
|
|
self._check_fixture("er")
|
|
|
|
|
|
|
|
|
|
def test_eri(self):
|
|
|
|
|
self._check_fixture("eri")
|
|
|
|
|
|
|
|
|
|
def test_fisher(self):
|
|
|
|
|
self._check_fixture("fisher")
|
|
|
|
|
|
|
|
|
|
def test_inertia(self):
|
|
|
|
|
self._check_fixture("inertia")
|
|
|
|
|
|
|
|
|
|
def test_kdj(self):
|
|
|
|
|
self._check_fixture("kdj")
|
|
|
|
|
|
|
|
|
|
def test_kst(self):
|
|
|
|
|
self._check_fixture("kst")
|
|
|
|
|
|
|
|
|
|
def test_lrsi(self):
|
|
|
|
|
self._check_fixture("lrsi")
|
|
|
|
|
|
|
|
|
|
def test_pgo_14(self):
|
|
|
|
|
self._check_fixture("pgo_14")
|
|
|
|
|
|
|
|
|
|
def test_po(self):
|
|
|
|
|
self._check_fixture("po")
|
|
|
|
|
|
|
|
|
|
def test_ppo(self):
|
|
|
|
|
self._check_fixture("ppo")
|
|
|
|
|
|
|
|
|
|
def test_psl(self):
|
|
|
|
|
self._check_fixture("psl")
|
|
|
|
|
|
|
|
|
|
def test_pvo(self):
|
|
|
|
|
self._check_fixture("pvo")
|
|
|
|
|
|
|
|
|
|
def test_qqe(self):
|
|
|
|
|
self._check_fixture("qqe")
|
|
|
|
|
|
|
|
|
|
def test_rsx(self):
|
|
|
|
|
self._check_fixture("rsx")
|
|
|
|
|
|
|
|
|
|
def test_rvgi(self):
|
|
|
|
|
self._check_fixture("rvgi")
|
|
|
|
|
|
|
|
|
|
def test_slope(self):
|
|
|
|
|
self._check_fixture("slope")
|
|
|
|
|
|
|
|
|
|
def test_smi(self):
|
|
|
|
|
self._check_fixture("smi")
|
|
|
|
|
|
|
|
|
|
def test_squeeze(self):
|
|
|
|
|
self._check_fixture("squeeze")
|
|
|
|
|
|
|
|
|
|
def test_squeeze_pro(self):
|
|
|
|
|
self._check_fixture("squeeze_pro")
|
|
|
|
|
|
|
|
|
|
def test_stc(self):
|
|
|
|
|
self._check_fixture("stc")
|
|
|
|
|
|
|
|
|
|
def test_stochrsi(self):
|
|
|
|
|
self._check_fixture("stochrsi")
|
|
|
|
|
|
|
|
|
|
def test_td_seq(self):
|
|
|
|
|
self._check_fixture("td_seq")
|
|
|
|
|
|
|
|
|
|
def test_trix(self):
|
|
|
|
|
self._check_fixture("trix")
|
|
|
|
|
|
|
|
|
|
def test_trixh(self):
|
|
|
|
|
self._check_fixture("trixh")
|
|
|
|
|
|
|
|
|
|
def test_tsi(self):
|
|
|
|
|
self._check_fixture("tsi")
|
|
|
|
|
|
|
|
|
|
def test_vwmacd(self):
|
|
|
|
|
self._check_fixture("vwmacd")
|
|
|
|
|
|
|
|
|
|
# Volatility — TA-Lib backed
|
|
|
|
|
def test_atr_14(self):
|
|
|
|
|
self._check_fixture("atr_14")
|
|
|
|
|
|
|
|
|
|
def test_bbands_20(self):
|
|
|
|
|
self._check_fixture("bbands_20")
|
|
|
|
|
|
|
|
|
|
def test_natr_14(self):
|
|
|
|
|
self._check_fixture("natr_14")
|
|
|
|
|
|
|
|
|
|
def test_true_range(self):
|
|
|
|
|
self._check_fixture("true_range")
|
|
|
|
|
|
|
|
|
|
# Volatility — native
|
|
|
|
|
def test_donchian_20(self):
|
|
|
|
|
self._check_fixture("donchian_20")
|
|
|
|
|
|
|
|
|
|
def test_kc_20(self):
|
|
|
|
|
self._check_fixture("kc_20")
|
|
|
|
|
|
|
|
|
|
def test_aberration(self):
|
|
|
|
|
self._check_fixture("aberration")
|
|
|
|
|
|
|
|
|
|
def test_accbands(self):
|
|
|
|
|
self._check_fixture("accbands")
|
|
|
|
|
|
|
|
|
|
def test_ce(self):
|
|
|
|
|
self._check_fixture("ce")
|
|
|
|
|
|
|
|
|
|
def test_hwc(self):
|
|
|
|
|
self._check_fixture("hwc")
|
|
|
|
|
|
|
|
|
|
def test_massi(self):
|
|
|
|
|
self._check_fixture("massi")
|
|
|
|
|
|
|
|
|
|
def test_pdist(self):
|
|
|
|
|
self._check_fixture("pdist")
|
|
|
|
|
|
|
|
|
|
def test_rvi_vol(self):
|
|
|
|
|
self._check_fixture("rvi_vol")
|
|
|
|
|
|
|
|
|
|
def test_thermo(self):
|
|
|
|
|
self._check_fixture("thermo")
|
|
|
|
|
|
|
|
|
|
def test_ui(self):
|
|
|
|
|
self._check_fixture("ui")
|
|
|
|
|
|
|
|
|
|
# Trend — TA-Lib backed
|
|
|
|
|
def test_adx_14(self):
|
|
|
|
|
self._check_fixture("adx_14")
|
|
|
|
|
|
|
|
|
|
def test_aroon_14(self):
|
|
|
|
|
self._check_fixture("aroon_14")
|
|
|
|
|
|
|
|
|
|
# Trend — native
|
|
|
|
|
def test_psar(self):
|
|
|
|
|
self._check_fixture("psar")
|
|
|
|
|
|
|
|
|
|
def test_decreasing(self):
|
|
|
|
|
self._check_fixture("decreasing")
|
|
|
|
|
|
|
|
|
|
def test_increasing(self):
|
|
|
|
|
self._check_fixture("increasing")
|
|
|
|
|
|
|
|
|
|
def test_adxr(self):
|
|
|
|
|
self._check_fixture("adxr")
|
|
|
|
|
|
|
|
|
|
def test_amat(self):
|
|
|
|
|
self._check_fixture("amat")
|
|
|
|
|
|
|
|
|
|
def test_chop(self):
|
|
|
|
|
self._check_fixture("chop")
|
|
|
|
|
|
|
|
|
|
def test_cksp(self):
|
|
|
|
|
self._check_fixture("cksp")
|
|
|
|
|
|
|
|
|
|
def test_cpr(self):
|
|
|
|
|
self._check_fixture("cpr")
|
|
|
|
|
|
|
|
|
|
def test_decay(self):
|
|
|
|
|
self._check_fixture("decay")
|
|
|
|
|
|
|
|
|
|
def test_dpo_14(self):
|
|
|
|
|
self._check_fixture("dpo_14")
|
|
|
|
|
|
|
|
|
|
def test_long_run(self):
|
|
|
|
|
self._check_fixture("long_run")
|
|
|
|
|
|
|
|
|
|
def test_pmax(self):
|
|
|
|
|
self._check_fixture("pmax")
|
|
|
|
|
|
|
|
|
|
def test_qstick(self):
|
|
|
|
|
self._check_fixture("qstick")
|
|
|
|
|
|
|
|
|
|
def test_short_run(self):
|
|
|
|
|
self._check_fixture("short_run")
|
|
|
|
|
|
|
|
|
|
def test_ttm_trend(self):
|
|
|
|
|
self._check_fixture("ttm_trend")
|
|
|
|
|
|
|
|
|
|
def test_vhf(self):
|
|
|
|
|
self._check_fixture("vhf")
|
|
|
|
|
|
|
|
|
|
def test_vortex(self):
|
|
|
|
|
self._check_fixture("vortex")
|
|
|
|
|
|
|
|
|
|
# Volume — TA-Lib backed
|
|
|
|
|
def test_obv(self):
|
|
|
|
|
self._check_fixture("obv")
|
|
|
|
|
|
|
|
|
|
def test_mfi_14(self):
|
|
|
|
|
self._check_fixture("mfi_14")
|
|
|
|
|
|
|
|
|
|
def test_ad(self):
|
|
|
|
|
self._check_fixture("ad")
|
|
|
|
|
|
|
|
|
|
def test_adosc(self):
|
|
|
|
|
self._check_fixture("adosc")
|
|
|
|
|
|
|
|
|
|
# Volume — native
|
|
|
|
|
def test_cmf_20(self):
|
|
|
|
|
self._check_fixture("cmf_20")
|
|
|
|
|
|
|
|
|
|
def test_aobv(self):
|
|
|
|
|
self._check_fixture("aobv")
|
|
|
|
|
|
|
|
|
|
def test_efi(self):
|
|
|
|
|
self._check_fixture("efi")
|
|
|
|
|
|
|
|
|
|
def test_eom(self):
|
|
|
|
|
self._check_fixture("eom")
|
|
|
|
|
|
|
|
|
|
def test_kvo(self):
|
|
|
|
|
self._check_fixture("kvo")
|
|
|
|
|
|
|
|
|
|
def test_nvi(self):
|
|
|
|
|
self._check_fixture("nvi")
|
|
|
|
|
|
|
|
|
|
def test_pvi(self):
|
|
|
|
|
self._check_fixture("pvi")
|
|
|
|
|
|
|
|
|
|
def test_pvol(self):
|
|
|
|
|
self._check_fixture("pvol")
|
|
|
|
|
|
|
|
|
|
def test_pvr(self):
|
|
|
|
|
self._check_fixture("pvr")
|
|
|
|
|
|
|
|
|
|
def test_pvt(self):
|
|
|
|
|
self._check_fixture("pvt")
|
|
|
|
|
|
|
|
|
|
def test_vfi(self):
|
|
|
|
|
self._check_fixture("vfi")
|
|
|
|
|
|
|
|
|
|
# Statistics — TA-Lib backed
|
|
|
|
|
def test_stdev_20(self):
|
|
|
|
|
self._check_fixture("stdev_20")
|
|
|
|
|
|
|
|
|
|
def test_variance_20(self):
|
|
|
|
|
self._check_fixture("variance_20")
|
|
|
|
|
|
|
|
|
|
# Statistics — native
|
|
|
|
|
def test_zscore_20(self):
|
|
|
|
|
self._check_fixture("zscore_20")
|
|
|
|
|
|
|
|
|
|
def test_kurtosis_20(self):
|
|
|
|
|
self._check_fixture("kurtosis_20")
|
|
|
|
|
|
|
|
|
|
def test_skew_20(self):
|
|
|
|
|
self._check_fixture("skew_20")
|
|
|
|
|
|
|
|
|
|
def test_beta(self):
|
|
|
|
|
self._check_fixture("beta")
|
|
|
|
|
|
|
|
|
|
def test_correl(self):
|
|
|
|
|
self._check_fixture("correl")
|
|
|
|
|
|
|
|
|
|
def test_entropy_10(self):
|
|
|
|
|
self._check_fixture("entropy_10")
|
|
|
|
|
|
|
|
|
|
def test_mad_10(self):
|
|
|
|
|
self._check_fixture("mad_10")
|
|
|
|
|
|
|
|
|
|
def test_median_14(self):
|
|
|
|
|
self._check_fixture("median_14")
|
|
|
|
|
|
|
|
|
|
def test_quantile_14(self):
|
|
|
|
|
self._check_fixture("quantile_14")
|
|
|
|
|
|
|
|
|
|
def test_tos_stdevall(self):
|
|
|
|
|
self._check_fixture("tos_stdevall")
|
|
|
|
|
|
|
|
|
|
# Cycles — TA-Lib backed
|
|
|
|
|
def test_ht_dcperiod(self):
|
|
|
|
|
self._check_fixture("ht_dcperiod")
|
|
|
|
|
|
|
|
|
|
def test_ht_dcphase(self):
|
|
|
|
|
self._check_fixture("ht_dcphase")
|
|
|
|
|
|
|
|
|
|
def test_ht_phasor(self):
|
|
|
|
|
self._check_fixture("ht_phasor")
|
|
|
|
|
|
|
|
|
|
def test_ht_sine(self):
|
|
|
|
|
self._check_fixture("ht_sine")
|
|
|
|
|
|
|
|
|
|
def test_ht_trendmode(self):
|
|
|
|
|
self._check_fixture("ht_trendmode")
|
|
|
|
|
|
|
|
|
|
def test_ht_trendline(self):
|
|
|
|
|
self._check_fixture("ht_trendline")
|
|
|
|
|
|
|
|
|
|
# Cycles — native
|
|
|
|
|
def test_dsp(self):
|
|
|
|
|
self._check_fixture("dsp")
|
|
|
|
|
|
|
|
|
|
def test_ebsw(self):
|
|
|
|
|
self._check_fixture("ebsw")
|
|
|
|
|
|
|
|
|
|
# Performance
|
|
|
|
|
def test_log_return(self):
|
|
|
|
|
self._check_fixture("log_return")
|
|
|
|
|
|
|
|
|
|
def test_percent_return(self):
|
|
|
|
|
self._check_fixture("percent_return")
|
|
|
|
|
|
|
|
|
|
def test_drawdown(self):
|
|
|
|
|
self._check_fixture("drawdown")
|
|
|
|
|
|
|
|
|
|
# Candles
|
|
|
|
|
def test_ha(self):
|
|
|
|
|
self._check_fixture("ha")
|
|
|
|
|
|
|
|
|
|
def test_cdl_doji(self):
|
|
|
|
|
self._check_fixture("cdl_doji")
|
|
|
|
|
|
|
|
|
|
def test_cdl_inside(self):
|
|
|
|
|
self._check_fixture("cdl_inside")
|
|
|
|
|
|
|
|
|
|
def test_cdl_z(self):
|
|
|
|
|
self._check_fixture("cdl_z")
|
|
|
|
|
|
|
|
|
|
# Overlap (additional)
|
|
|
|
|
def test_ichimoku(self):
|
|
|
|
|
self._check_fixture("ichimoku")
|
|
|
|
|
|
|
|
|
|
def test_ma_ema_20(self):
|
|
|
|
|
self._check_fixture("ma_ema_20")
|
|
|
|
|
|
|
|
|
|
# Trend (additional)
|
|
|
|
|
def test_tsignals(self):
|
|
|
|
|
self._check_fixture("tsignals")
|
|
|
|
|
|
|
|
|
|
def test_xsignals(self):
|
|
|
|
|
self._check_fixture("xsignals")
|
|
|
|
|
|
|
|
|
|
# Volume (additional)
|
|
|
|
|
def test_vp(self):
|
|
|
|
|
self._check_fixture("vp")
|
|
|
|
|
|
|
|
|
|
# Candles — CDL patterns (via dispatcher)
|
|
|
|
|
def test_cdl_pattern(self):
|
|
|
|
|
self._check_fixture("cdl_pattern")
|
|
|
|
|
|
|
|
|
|
def test_cdl_2crows(self):
|
|
|
|
|
self._check_fixture("cdl_2crows")
|
|
|
|
|
|
|
|
|
|
def test_cdl_3blackcrows(self):
|
|
|
|
|
self._check_fixture("cdl_3blackcrows")
|
|
|
|
|
|
|
|
|
|
def test_cdl_3inside(self):
|
|
|
|
|
self._check_fixture("cdl_3inside")
|
|
|
|
|
|
|
|
|
|
def test_cdl_3linestrike(self):
|
|
|
|
|
self._check_fixture("cdl_3linestrike")
|
|
|
|
|
|
|
|
|
|
def test_cdl_3outside(self):
|
|
|
|
|
self._check_fixture("cdl_3outside")
|
|
|
|
|
|
|
|
|
|
def test_cdl_3starsinsouth(self):
|
|
|
|
|
self._check_fixture("cdl_3starsinsouth")
|
|
|
|
|
|
|
|
|
|
def test_cdl_3whitesoldiers(self):
|
|
|
|
|
self._check_fixture("cdl_3whitesoldiers")
|
|
|
|
|
|
|
|
|
|
def test_cdl_abandonedbaby(self):
|
|
|
|
|
self._check_fixture("cdl_abandonedbaby")
|
|
|
|
|
|
|
|
|
|
def test_cdl_advanceblock(self):
|
|
|
|
|
self._check_fixture("cdl_advanceblock")
|
|
|
|
|
|
|
|
|
|
def test_cdl_belthold(self):
|
|
|
|
|
self._check_fixture("cdl_belthold")
|
|
|
|
|
|
|
|
|
|
def test_cdl_breakaway(self):
|
|
|
|
|
self._check_fixture("cdl_breakaway")
|
|
|
|
|
|
|
|
|
|
def test_cdl_closingmarubozu(self):
|
|
|
|
|
self._check_fixture("cdl_closingmarubozu")
|
|
|
|
|
|
|
|
|
|
def test_cdl_concealbabyswall(self):
|
|
|
|
|
self._check_fixture("cdl_concealbabyswall")
|
|
|
|
|
|
|
|
|
|
def test_cdl_counterattack(self):
|
|
|
|
|
self._check_fixture("cdl_counterattack")
|
|
|
|
|
|
|
|
|
|
def test_cdl_darkcloudcover(self):
|
|
|
|
|
self._check_fixture("cdl_darkcloudcover")
|
|
|
|
|
|
|
|
|
|
def test_cdl_dojistar(self):
|
|
|
|
|
self._check_fixture("cdl_dojistar")
|
|
|
|
|
|
|
|
|
|
def test_cdl_dragonflydoji(self):
|
|
|
|
|
self._check_fixture("cdl_dragonflydoji")
|
|
|
|
|
|
|
|
|
|
def test_cdl_engulfing(self):
|
|
|
|
|
self._check_fixture("cdl_engulfing")
|
|
|
|
|
|
|
|
|
|
def test_cdl_eveningdojistar(self):
|
|
|
|
|
self._check_fixture("cdl_eveningdojistar")
|
|
|
|
|
|
|
|
|
|
def test_cdl_eveningstar(self):
|
|
|
|
|
self._check_fixture("cdl_eveningstar")
|
|
|
|
|
|
|
|
|
|
def test_cdl_gapsidesidewhite(self):
|
|
|
|
|
self._check_fixture("cdl_gapsidesidewhite")
|
|
|
|
|
|
|
|
|
|
def test_cdl_gravestonedoji(self):
|
|
|
|
|
self._check_fixture("cdl_gravestonedoji")
|
|
|
|
|
|
|
|
|
|
def test_cdl_hammer(self):
|
|
|
|
|
self._check_fixture("cdl_hammer")
|
|
|
|
|
|
|
|
|
|
def test_cdl_hangingman(self):
|
|
|
|
|
self._check_fixture("cdl_hangingman")
|
|
|
|
|
|
|
|
|
|
def test_cdl_harami(self):
|
|
|
|
|
self._check_fixture("cdl_harami")
|
|
|
|
|
|
|
|
|
|
def test_cdl_haramicross(self):
|
|
|
|
|
self._check_fixture("cdl_haramicross")
|
|
|
|
|
|
|
|
|
|
def test_cdl_highwave(self):
|
|
|
|
|
self._check_fixture("cdl_highwave")
|
|
|
|
|
|
|
|
|
|
def test_cdl_hikkake(self):
|
|
|
|
|
self._check_fixture("cdl_hikkake")
|
|
|
|
|
|
|
|
|
|
def test_cdl_hikkakemod(self):
|
|
|
|
|
self._check_fixture("cdl_hikkakemod")
|
|
|
|
|
|
|
|
|
|
def test_cdl_homingpigeon(self):
|
|
|
|
|
self._check_fixture("cdl_homingpigeon")
|
|
|
|
|
|
|
|
|
|
def test_cdl_identical3crows(self):
|
|
|
|
|
self._check_fixture("cdl_identical3crows")
|
|
|
|
|
|
|
|
|
|
def test_cdl_inneck(self):
|
|
|
|
|
self._check_fixture("cdl_inneck")
|
|
|
|
|
|
|
|
|
|
def test_cdl_invertedhammer(self):
|
|
|
|
|
self._check_fixture("cdl_invertedhammer")
|
|
|
|
|
|
|
|
|
|
def test_cdl_kicking(self):
|
|
|
|
|
self._check_fixture("cdl_kicking")
|
|
|
|
|
|
|
|
|
|
def test_cdl_kickingbylength(self):
|
|
|
|
|
self._check_fixture("cdl_kickingbylength")
|
|
|
|
|
|
|
|
|
|
def test_cdl_ladderbottom(self):
|
|
|
|
|
self._check_fixture("cdl_ladderbottom")
|
|
|
|
|
|
|
|
|
|
def test_cdl_longleggeddoji(self):
|
|
|
|
|
self._check_fixture("cdl_longleggeddoji")
|
|
|
|
|
|
|
|
|
|
def test_cdl_longline(self):
|
|
|
|
|
self._check_fixture("cdl_longline")
|
|
|
|
|
|
|
|
|
|
def test_cdl_marubozu(self):
|
|
|
|
|
self._check_fixture("cdl_marubozu")
|
|
|
|
|
|
|
|
|
|
def test_cdl_matchinglow(self):
|
|
|
|
|
self._check_fixture("cdl_matchinglow")
|
|
|
|
|
|
|
|
|
|
def test_cdl_mathold(self):
|
|
|
|
|
self._check_fixture("cdl_mathold")
|
|
|
|
|
|
|
|
|
|
def test_cdl_morningdojistar(self):
|
|
|
|
|
self._check_fixture("cdl_morningdojistar")
|
|
|
|
|
|
|
|
|
|
def test_cdl_morningstar(self):
|
|
|
|
|
self._check_fixture("cdl_morningstar")
|
|
|
|
|
|
|
|
|
|
def test_cdl_onneck(self):
|
|
|
|
|
self._check_fixture("cdl_onneck")
|
|
|
|
|
|
|
|
|
|
def test_cdl_piercing(self):
|
|
|
|
|
self._check_fixture("cdl_piercing")
|
|
|
|
|
|
|
|
|
|
def test_cdl_rickshawman(self):
|
|
|
|
|
self._check_fixture("cdl_rickshawman")
|
|
|
|
|
|
|
|
|
|
def test_cdl_risefall3methods(self):
|
|
|
|
|
self._check_fixture("cdl_risefall3methods")
|
|
|
|
|
|
|
|
|
|
def test_cdl_separatinglines(self):
|
|
|
|
|
self._check_fixture("cdl_separatinglines")
|
|
|
|
|
|
|
|
|
|
def test_cdl_shootingstar(self):
|
|
|
|
|
self._check_fixture("cdl_shootingstar")
|
|
|
|
|
|
|
|
|
|
def test_cdl_shortline(self):
|
|
|
|
|
self._check_fixture("cdl_shortline")
|
|
|
|
|
|
|
|
|
|
def test_cdl_spinningtop(self):
|
|
|
|
|
self._check_fixture("cdl_spinningtop")
|
|
|
|
|
|
|
|
|
|
def test_cdl_stalledpattern(self):
|
|
|
|
|
self._check_fixture("cdl_stalledpattern")
|
|
|
|
|
|
|
|
|
|
def test_cdl_sticksandwich(self):
|
|
|
|
|
self._check_fixture("cdl_sticksandwich")
|
|
|
|
|
|
|
|
|
|
def test_cdl_takuri(self):
|
|
|
|
|
self._check_fixture("cdl_takuri")
|
|
|
|
|
|
|
|
|
|
def test_cdl_tasukigap(self):
|
|
|
|
|
self._check_fixture("cdl_tasukigap")
|
|
|
|
|
|
|
|
|
|
def test_cdl_thrusting(self):
|
|
|
|
|
self._check_fixture("cdl_thrusting")
|
|
|
|
|
|
|
|
|
|
def test_cdl_tristar(self):
|
|
|
|
|
self._check_fixture("cdl_tristar")
|
|
|
|
|
|
|
|
|
|
def test_cdl_unique3river(self):
|
|
|
|
|
self._check_fixture("cdl_unique3river")
|
|
|
|
|
|
|
|
|
|
def test_cdl_upsidegap2crows(self):
|
|
|
|
|
self._check_fixture("cdl_upsidegap2crows")
|
|
|
|
|
|
|
|
|
|
def test_cdl_xsidegap3methods(self):
|
|
|
|
|
self._check_fixture("cdl_xsidegap3methods")
|