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---2project: anomaly-atlas3document: Artifact taxonomy4author: Simon-Pierre Boucher5contact: contact@spboucher.ai6data_source: hfmarketdata.io7created: 2026-08-128modified: 2026-08-129status: reviewed10---1112# Artifact taxonomy (living document)1314The catalogue of mechanisms **in this specific dataset** that manufacture15fake anomalies — a primary deliverable (Q4). Every entry: mechanism,16detection, measured magnitude on this data, neutralization. Magnitudes from17`results/expA_data_reality/20260812T054515Z/` and18`results/expB_artifact_baselines/20260812T055602Z/` (Q1 2024, RTH 1min,19pre-specified universe). Detectors validated on synthetic ground truth first20(`benchmarks/synthetic/test_synthetic_gate.py`, 11 tests).2122## T1 — Bid-ask bounce (Roll)2324* **Mechanism.** Trades alternate bid/ask; observed returns gain a negative25 lag-1 autocovariance (−s²/4) with no economics. Masquerades as26 mean-reversion (Q1).27* **Detection.** Roll implied relative spread `2·√(−autocov1)`;28 bounce-implied AC1; `excess_reversion()` (validation/artifacts.py).29* **Measured.** Median AC1 by staleness tercile: −0.009 (fresh) / −0.05130 (mid) / **−0.232 (stale)**; Roll spread 1.4 / 3.8 / 17.0 bp. Mega-caps:31 no measurable bounce (AC1 CI covers 0; Roll undefined ~half the time —32 positive autocov).33* **Neutralize.** Report reversion net of the liquidity-bucket bounce null;34 never average AC1 across liquidity buckets; treat Roll-undefined as35 "no bounce measurable", not zero spread.36* **expC amendment (measured).** A daily *effective* spread (EDGE) combined37 with pure Roll alternation predicts impossible intraday AC1 (−3 to −27):38 consecutive intraday closes do not flip sides each bar. Spread-based39 bounce nulls MUST be variance-consistent with the target series; for40 intraday scans use the MA(1)-consistent VR null41 (VR_null(q) = 1 + 2·AC1·(1−1/q)) — conservative, absorbs all lag-142 effects.4344## T2 — Stale prices / missing minutes4546* **Mechanism.** Bars exist only where trades occurred (expA: zero47 zero-volume bars; an illiquid name printed 38 bars/day). LOCF joins add a48 large mass of zero returns and depress variance-ratio statistics.49* **Detection.** `staleness_ratio` on the 390-min RTH grid.50* **Measured.** Staleness up to 0.90 (RITM.B); **VR(30) = 0.55 median for51 the stale tercile — 0.35 extreme — with zero planted economics.** 11/4252 pre-specified tickers had too little data to analyze at all.53* **Neutralize.** Explicit grids with observed-masks (never silent LOCF);54 liquidity filters pre-specified; VR/AC1 claims benchmarked against the55 staleness-matched null, not against 1.0.5657## T3 — Non-synchronous lead-lag (LOCF cross-correlation)5859* **Mechanism.** A fresh series LOCF-joined to a stale one appears to LEAD60 it: the stale print reflects old common information (classic61 non-synchronous trading bias).62* **Detection.** Lagged cross-correlation vs SPY on the LOCF grid; synthetic63 ground truth: rho=0.7 pair with 30 % observation → spurious +1 lag corr.64* **Measured.** SPY "leads" mid-staleness tickers by +0.047 at +1 min65 (Spearman vs staleness +0.43). **SPX-vs-SPY: +0.065 with SPY leading66 1 min** at 0.965 contemporaneous corr — index prints lag the ETF.67* **Neutralize.** Any Q2 lead-lag claim must exceed the staleness-predicted68 cross-correlation; test on synchronized (both-fresh) subsamples; index69 series are stale by construction.70* **expD amendments (measured).** (i) The artifact is NON-MONOTONE in71 staleness: LOCF joins inflate leads for mid-stale names (+0.047, expB) but72 DILUTE them for ultra-stale names (HTD raw +0.048 vs both-fresh +0.073) —73 naive joins can hide lead-lag as well as manufacture it. (ii) For computed74 indices, synchronizing on PRINT times removes nothing: SPY leads SPX75 +0.132 both-fresh (fresh_frac 0.996) — content staleness must be modeled,76 not print gaps.7778## T4 — Auction close vs last bar7980* **Mechanism.** Daily bars carry the official closing-auction print; 1min81 bars do not (expA: AAPL 312.41 daily close vs 312.49 last RTH 1min close).82 Mixing conventions manufactures phantom overnight/close-to-close returns.83* **Measured.** 8 bp discrepancy on a calm day for the most liquid stock.84* **Neutralize.** Pick ONE close convention per experiment and state it;85 never compute overnight returns across mixed conventions.8687## T5 — Rolling adjustment anchor8889* **Mechanism.** `adj_splitdiv` re-bases the whole history to the dataset90 build date (expA: AAPL 2020-08-31 close = 125.17 adjusted vs 129.0491 traded). Adjusted series are not point-in-time stable → silent look-ahead92 and irreproducibility if the cache is refreshed mid-study.93* **Neutralize.** Frozen local cache (hf_client never silently refetches);94 data-manifest hash in every provenance; intraday work uses within-day95 returns (adjustment-invariant) or UNADJUSTED plus explicit factors.9697## T6 — Daily vs intraday volume conventions9899* **Mechanism.** Daily volume includes auction/consolidated prints absent100 from 1min bars (expA: 46.1 M daily vs 34.7 M extended-1min sum vs 25.7 M101 RTH-1min sum for AAPL on one day — a 1.8× spread across conventions).102* **Neutralize.** Volume-based signals pick one convention; never mix daily103 and intraday volume in one feature.104105## T7 — Vendor session / timezone semantics106107* **Mechanism.** All timestamps are US/Eastern wall-clock without a marker;108 sessions differ per class (equities 04:00–19:59, SPX prints to 16:20,109 futures ≈24 h, fx ET-week, crypto 24/7). Cross-asset joins on naive110 timestamps silently compare different market states.111* **Neutralize.** One canonical calendar module (`data/calendars.py`),112 explicit session filters per asset class, DST-aware conversions.113114---115116**T1/T2 intraday profile (measured, expE/H20 — liquid 12, 1min, 2014-2015).**117Volatility is U-shaped: median |1min return| 6.6 bp at 09:30 → 2.4 bp midday118→ 2.9 bp at 15:30. The EDGE spread declines monotonically 2.8 → 1.2 bp (an119L, not a U). Consequence: intraday return claims concentrated at the open120face 2–3× the midday artifact level and double the closing spread — expE/expG121must bucket-match their nulls and costs by time of day.122123*Open items: continuous-futures splice choice (3 variants exposed by the124API) as a testable artifact for futures-based hypotheses — expD found the125ES→SPY cross-serial effect splice-INVARIANT, so the residual exposure is126futures-only level/trend work.*127