mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-28 17:57:45 +00:00
81 lines
2.7 KiB
Python
81 lines
2.7 KiB
Python
from __future__ import annotations
|
|
|
|
import numpy as np
|
|
import pandas as pd
|
|
import pandas_ta as ta
|
|
import pytest
|
|
|
|
from quantalib import indicators as q
|
|
|
|
|
|
SEED = 42
|
|
N = 10_000
|
|
VERIFY_COUNT = 100
|
|
|
|
|
|
def _generate_gbm(
|
|
n: int,
|
|
seed: int = SEED,
|
|
start_price: float = 100.0,
|
|
mu: float = 0.05,
|
|
sigma: float = 0.2,
|
|
dt: float = 1 / 252,
|
|
) -> np.ndarray:
|
|
rng = np.random.default_rng(seed)
|
|
z = rng.standard_normal(n - 1)
|
|
drift = (mu - 0.5 * sigma**2) * dt
|
|
diffusion = sigma * np.sqrt(dt) * z
|
|
log_returns = drift + diffusion
|
|
|
|
prices = np.empty(n, dtype=np.float64)
|
|
prices[0] = start_price
|
|
np.cumsum(log_returns, out=prices[1:])
|
|
prices[1:] += np.log(start_price)
|
|
np.exp(prices[1:], out=prices[1:])
|
|
prices[0] = start_price
|
|
return prices
|
|
|
|
|
|
CLOSE = _generate_gbm(N)
|
|
SERIES = pd.Series(CLOSE, name="close")
|
|
|
|
|
|
def _verify_last_n(
|
|
qtl_arr: np.ndarray,
|
|
pta_arr: np.ndarray,
|
|
*,
|
|
verify_count: int = VERIFY_COUNT,
|
|
tolerance: float = 1e-6,
|
|
label: str,
|
|
) -> None:
|
|
assert len(qtl_arr) == len(pta_arr), f"{label}: length mismatch"
|
|
|
|
start = max(0, len(qtl_arr) - verify_count)
|
|
q_tail = qtl_arr[start:]
|
|
p_tail = pta_arr[start:]
|
|
|
|
finite = np.isfinite(q_tail) & np.isfinite(p_tail)
|
|
assert int(np.sum(finite)) > 0, f"{label}: no finite overlap in tail"
|
|
|
|
diff = np.abs(q_tail[finite] - p_tail[finite])
|
|
max_diff = float(np.max(diff))
|
|
assert max_diff <= tolerance, f"{label}: max_diff={max_diff:.3e} > tol={tolerance:.1e}"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"name,qtl,pta,tol",
|
|
[
|
|
("rsi_14", q.rsi(CLOSE, length=14), ta.rsi(SERIES, length=14).to_numpy(), 1e-6),
|
|
("mom_10", q.mom(CLOSE, length=10), ta.mom(SERIES, length=10).to_numpy(), 1e-9),
|
|
("cmo_14", q.cmo(CLOSE, length=14), ta.cmo(SERIES, length=14, talib=False).to_numpy(), 1e-6),
|
|
("apo_12_26", q.apo(CLOSE, fast=12, slow=26), ta.apo(SERIES, fast=12, slow=26, mamode="ema", talib=False).to_numpy(), 1e-6),
|
|
("bias_26", q.bias(CLOSE, length=26), ta.bias(SERIES, length=26).to_numpy(), 1e-6),
|
|
("cfo_14", q.cfo(CLOSE, length=14), (100.0 * (SERIES - ta.linreg(SERIES, length=14, tsf=False, talib=False)) / SERIES).to_numpy(), 1e-6),
|
|
("dpo_20", q.dpo(CLOSE, length=20), ta.dpo(SERIES, length=20, centered=False).to_numpy(), 1e-6),
|
|
("trix_18", q.trix(CLOSE, length=18), ta.trix(SERIES, length=18).iloc[:, 0].to_numpy(), 1e-6),
|
|
("er_10", q.er(CLOSE, length=10), ta.er(SERIES, length=10).to_numpy(), 1e-6),
|
|
("cti_12", q.cti(CLOSE, length=12), ta.cti(SERIES, length=12).to_numpy(), 1e-6),
|
|
],
|
|
)
|
|
def test_pandas_ta_parity_batch_01(name: str, qtl: np.ndarray, pta: np.ndarray, tol: float) -> None:
|
|
_verify_last_n(qtl, pta, tolerance=tol, label=name) |