SPB Git

spb/wp40_uqo

Public MIT
4.8 KB · 92 lines python
1"""pytest for the Python layer (requires the compiled core on sys.path: build with -DRAID_BUILD_PYTHON=ON)."""2import os, sys3import numpy as np4import pytest56sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))7raid = pytest.importorskip("raid")8if not raid.HAS_CORE:9    pytest.skip("raid._core not built", allow_module_level=True)101112def test_devices_has_cpu():13    kinds = [d["kind"] for d in raid.devices()]14    assert "cpu" in kinds151617def test_ols_matches_statsmodels_hc3():18    sm = pytest.importorskip("statsmodels.api")19    rng = np.random.default_rng(3); X = np.column_stack([np.ones(400), rng.normal(size=400), rng.normal(size=400)]); y = X @ [1, 2, -1] + rng.normal(size=400) * (1 + X[:, 1] ** 2)20    e = raid.ols(X, y, cov="hc3"); f = sm.OLS(y, X).fit(cov_type="HC3")21    np.testing.assert_allclose(e["coefficients"], f.params, rtol=1e-10)22    np.testing.assert_allclose(e["inference"]["std_errors"], f.bse, rtol=1e-9)23    assert e["ok"] and e["backend"] == "cpu" and e["precision"] == "fp64"242526def test_ols_rejects_nan():27    with pytest.raises(ValueError):28        raid.ols(np.array([[1.0, np.nan]]), np.array([1.0]))293031def test_realized_measures_cpu_matches_numpy():32    rng = np.random.default_rng(5); r = rng.normal(0, 1e-3, size=390 * 10); off = np.arange(0, 3901, 390)33    m = raid.realized_measures(r, off, backend="cpu")34    for k in range(10):35        seg = r[off[k]:off[k + 1]]36        assert abs(m["rv"][k] - np.sum(seg ** 2)) <= 1e-15 * np.sum(seg ** 2) * 1037        assert abs(m["rsv_neg"][k] + m["rsv_pos"][k] - m["rv"][k]) <= 1e-1838    assert m["backend"] == "cpu"394041def test_garch_fit_converges_and_forecasts():42    rng = np.random.default_rng(9); n = 2500; r = np.empty(n); s2 = 1e-4; e = 0.043    for t in range(n):44        s2 = 1e-6 + 0.08 * e * e + 0.9 * s2; e = np.sqrt(s2) * rng.standard_normal(); r[t] = e45    g = raid.garch_fit(r, model="garch", dist="gaussian", horizon=5)46    assert g["ok"] and g["convergence"]["converged"]47    assert abs(g["coefficients"][3] - 0.9) < 0.08 and len(g["extra"]["forecast_variance"]) == 5484950def test_calendar_sessions_thanksgiving_week():51    assert raid.calendar_sessions("2024-11-25", "2024-11-29") == ["2024-11-25", "2024-11-26", "2024-11-27", "2024-11-29"]525354def test_validate_bars_counts_missing():55    # one session, 391 regular minutes 2024-11-27 (09:30–16:00 ET = 14:30–21:00 UTC), drop 3 bars56    base = np.datetime64("2024-11-27T14:30:00").astype("datetime64[us]").astype(np.int64)57    t = base + np.arange(391) * 60_000_000; keep = np.ones(391, bool); keep[[10, 20, 30]] = False; t = t[keep]58    p = 100 + np.cumsum(np.random.default_rng(1).normal(0, 0.01, size=t.size))59    q = raid.validate_bars(t, p, p + 0.01, p - 0.01, p, np.full(t.size, 100.0))60    assert q["n_sessions"] == 1 and q["missing_regular_bars"] == 3 and not q["has_errors"]616263def test_har_fit_matches_statsmodels_hac():64    sm = pytest.importorskip("statsmodels.api")65    rng = np.random.default_rng(8); T = 800; lv = np.empty(T); lv[0] = np.log(1e-4)66    for t in range(1, T): lv[t] = 0.3 * np.log(1e-4) + 0.7 * lv[t - 1] + 0.4 * rng.standard_normal()67    rv = np.exp(lv); e = raid.har_fit(rv, horizon=1)68    rows = []; ys = []69    for t in range(21, T - 1):70        rows.append([1.0, rv[t], rv[t - 4:t + 1].mean(), rv[t - 21:t + 1].mean()]); ys.append(rv[t + 1])71    X = np.array(rows); y = np.array(ys); L = max(0, int(np.floor(4 * (len(y) / 100) ** (2 / 9))))72    f = sm.OLS(y, X).fit(cov_type="HAC", cov_kwds={"maxlags": L, "use_correction": False})73    np.testing.assert_allclose(e["coefficients"], f.params, rtol=1e-9); np.testing.assert_allclose(e["inference"]["std_errors"], f.bse, rtol=1e-8)74    assert e["forecast_next"] > 075    r = raid.har_rolling(rv, horizon=5, window=400, step=20); assert r["n_fits"] > 10 and r["qlike"] >= 076    b = raid.har_batch(np.concatenate([rv, rv * 2]), np.array([0, T, 2 * T]), backend="auto"); assert len(b["fits"]) == 2 and b["fits"][1]["ok"]777879def test_bootstrap_block_vs_iid():80    rng = np.random.default_rng(2); n = 1500; x = np.empty(n); x[0] = 081    for t in range(1, n): x[t] = 0.7 * x[t - 1] + rng.standard_normal()82    blk = raid.bootstrap(x, "mean", "stationary", mean_block=20, replicas=399); iid = raid.bootstrap(x, "mean", "iid", replicas=399)83    assert blk["se"] > 1.5 * iid["se"] and blk["failures"] == 0 and blk["ci_lo"] < blk["point"] < blk["ci_hi"]848586def test_var_connectedness_matches_statsmodels_shape_and_bounds():87    rng = np.random.default_rng(4); T, N = 600, 3; Y = np.zeros((T, N)); A = np.array([[0.5, 0.1, 0.0], [0.0, 0.4, 0.2], [0.1, 0.0, 0.3]])88    for t in range(1, T): Y[t] = A @ Y[t - 1] + rng.standard_normal(N)89    c = raid.var_connectedness(Y, p=1, H=10, window=300, step=50)90    assert c["stable"] and 0 <= c["total"] <= 100 and np.allclose(c["table"].sum(axis=1), 1.0) and c["rolling_failures"] == 091    lw = raid.ledoit_wolf(Y); assert 0 <= lw["shrinkage"] <= 1 and lw["cov"].shape == (N, N)92
Files · main
Menu

Theme