SPB Git

spb/anomaly-atlas Public License

Systematic discovery & rigorous validation of statistical anomalies in open HF market data (hfmarketdata.io) — pre-registered, artifact-null-driven, fully reproducible. Live atlas: www.anomaly-atlas.io

Python 61.4% JavaScript 28.7% CSS 8.6% Shell 0.7% Makefile 0.5%
1.9 KB · 59 lines python
Raw Blame History
1# =============================================================================2#  Project   : anomaly-atlas3#  File      : src/anomaly_atlas/stats/bootstrap.py4#  Purpose   : Moving-block bootstrap and percentile confidence intervals5#  Author    : Simon-Pierre Boucher6#  Contact   : contact@spboucher.ai7#  Data src  : hfmarketdata.io (sole data source)8#  Created   : 2026-08-129#  Modified  : 2026-08-1210#  Platform  : macOS / Apple Silicon (arm64)11#  License   : All rights reserved (research code)12# =============================================================================13"""Moving-block bootstrap for serially dependent data (Künsch 1989).1415Blocks preserve short-range dependence, so statistics like AC1 or variance16ratios get honest sampling distributions. Every call takes an explicit seed.17"""1819from __future__ import annotations2021from collections.abc import Callable2223import numpy as np242526def moving_block_bootstrap(27    x: np.ndarray,28    stat: Callable[[np.ndarray], float],29    block: int,30    n_boot: int = 500,31    seed: int = 0,32) -> np.ndarray:33    """Bootstrap distribution of `stat` using moving blocks of length `block`."""34    x = np.asarray(x, dtype=float)35    n = len(x)36    if n < 2 * block:37        return np.array([])38    rng = np.random.default_rng(seed)39    n_blocks = int(np.ceil(n / block))40    starts_max = n - block + 141    out = np.empty(n_boot)42    for i in range(n_boot):43        starts = rng.integers(0, starts_max, n_blocks)44        sample = np.concatenate([x[s : s + block] for s in starts])[:n]45        out[i] = stat(sample)46    return out474849def percentile_ci(samples: np.ndarray, alpha: float = 0.05) -> tuple[float, float]:50    """Two-sided percentile confidence interval."""51    s = np.asarray(samples, dtype=float)52    s = s[np.isfinite(s)]53    if len(s) == 0:54        return (float("nan"), float("nan"))55    return (56        float(np.percentile(s, 100 * alpha / 2)),57        float(np.percentile(s, 100 * (1 - alpha / 2))),58    )59