"""NumPy-facing wrappers over the compiled core (``raid._core``). All heavy work releases the GIL in C++.""" from __future__ import annotations import enum from typing import Any, Mapping, Sequence import numpy as np class Backend(str, enum.Enum): auto = "auto" cpu = "cpu" metal = "metal" def _core(): from . import _core as c # noqa: WPS433 if c is None: raise ImportError("raid._core is not built; install the wheel or build with -DRAID_BUILD_PYTHON=ON") return c def devices() -> list[dict[str, Any]]: """List the available compute devices (CPU always; Metal when built and present).""" return _core().devices() def available_backends() -> list[str]: return [d["kind"] for d in devices()] def _f64(x) -> np.ndarray: a = np.ascontiguousarray(x, dtype=np.float64) if not np.isfinite(a).all(): raise ValueError("non-finite values in input (RAID never imputes silently)") return a def ols(X, y, cov: str = "classical", hac_lags: int = -1, clusters=None, ridge_lambda: float = 0.0, unpenalized: Sequence[int] = (), weights=None, names: Sequence[str] | None = None) -> dict[str, Any]: """OLS/WLS/ridge with classical, HC0–HC3, HAC (Bartlett) or one-way cluster covariance. Returns an Estimate dict.""" X = _f64(X); y = _f64(y) if X.ndim != 2 or y.ndim != 1 or X.shape[0] != y.shape[0]: raise ValueError("X must be (n, k) and y (n,)") cl = None if clusters is None else np.ascontiguousarray(clusters, dtype=np.int64) w = None if weights is None else _f64(weights) return _core().ols(X, y, cov, int(hac_lags), cl, float(ridge_lambda), list(unpenalized), w, list(names or [])) def realized_measures(returns, offsets, backend: str | Backend = Backend.auto, bpv_finite_sample: bool = True, deterministic: bool = True) -> dict[str, np.ndarray]: """Per-segment realized measures from concatenated intraday returns and CSR offsets (n_segments + 1).""" r = _f64(returns); off = np.ascontiguousarray(offsets, dtype=np.int64) return _core().realized_measures(r, off, str(Backend(backend).value), bool(bpv_finite_sample), bool(deterministic)) def garch_fit(returns, model: str = "garch", dist: str = "gaussian", horizon: int = 0, cov: str = "qmle", max_iter: int = 500, tol: float = 1e-8) -> dict[str, Any]: """QML fit of GARCH(1,1) / GJR / EGARCH with Gaussian or Student-t errors (CPU FP64).""" return _core().garch_fit(_f64(returns), model, dist, int(horizon), cov, int(max_iter), float(tol)) def validate_bars(timestamps_us, open_, high, low, close, volume, symbol: str = "", interval: str = "1m", session: str = "regular") -> dict[str, Any]: """Quality report of one bar series (timestamps = bar open, microseconds UTC).""" t = np.ascontiguousarray(timestamps_us, dtype=np.int64) return _core().validate_bars(t, _f64(open_), _f64(high), _f64(low), _f64(close), _f64(volume), symbol, interval, session) def calendar_sessions(start: str, end: str) -> list[str]: """XNYS trading sessions in [start, end] (ISO dates).""" return _core().calendar_sessions(start, end) def bars_to_intraday_returns(timestamps_us, close, kind: str = "log") -> dict[str, np.ndarray]: """Session-aware intraday log/arithmetic returns from (bar open timestamp, close) arrays; returns CSR layout.""" t = np.ascontiguousarray(timestamps_us, dtype=np.int64) return _core().intraday_returns(t, _f64(close), kind)