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%
13.3 KB

# project: anomaly-atlas document: Research log author: Simon-Pierre Boucher contact: contact@spboucher.ai data_source: hfmarketdata.io created: 2026-08-12 status: draft

# Research log — anomaly-atlas

Append-only. Every entry: date/time+timezone, question, experiment, result, interpretation, decision (CLAUDE.md §12).

# 2026-08-12 21:00 ET — Project bootstrap

Question. None yet — administrative.

Action. Repository scaffolded per CLAUDE.md §3, mirroring the localvm-research layout (the site/ of the charter is implemented as web/, a Node/Express research-showcase platform, like localvm-research). Author headers with the mandatory Data src: hfmarketdata.io field on every source file; tools/check_headers.py enforces them. Web platform deployed on MacLustr node M3U96b (port 8150) behind ngrok at www.anomaly-atlas.io.

Decision. Next step is Phase 0.5 / Experiment A (data reality check): establish empirically what hfmarketdata.io actually provides before any methodology is designed. No statistical work before the detectors pass the synthetic-series tests (§8.1).

# 2026-08-12 01:50 ET — Phase 0.5 complete: Experiment A (data reality check)

Question. What does hfmarketdata.io actually provide (granularity, depth, timestamps, adjustments, completeness, limits)?

Experiment. expA_data_reality — 8 probe families through the newly implemented single client (hf_client.py: cache-first, throttled, back-off, data-manifest index; 5 offline unit tests pass). 54 network requests, 274 571 rows; re-run served 100 % from cache (0 network requests).

Result. 1min granularity is real; stock/etf from 2000, futures/index 2008, fx 2010, crypto 2013; options daily chains 2010→2026 (67 quarters). Timestamps US/Eastern bar-start. Archive lags ~2–5 days. Hard 50k-row cap (client paginates, verified 218 006 rows, 0 dupes). Split arithmetic exact; adj_splitdiv re-bases history to build date. No zero-volume bars — missing minutes are real gaps. Daily bars = RTH + auction close + consolidated volume NOT present in 1min bars.

Interpretation. Dataset is fit for Q1–Q3. Four built-in artifact mechanisms identified (non-synchronous sessions, stale prints, auction-close mismatch, rolling adjustment anchor) — these seed the artifact taxonomy and the expB nulls.

Decision. Full findings in research/data_source_profile.md (status: reviewed). Next: expB_artifact_baselines + Phase 1 literature sweep.

# 2026-08-12 02:15 ET — expB complete: artifact nulls measured (after the §8.1 gate caught a real bug)

Question. Are the bounce/staleness/non-synchronicity artifacts measurable and material at 1min on this data?

Experiment. Built generators with known ground truth + first real stats modules (reversion, leadlag, bootstrap, artifacts). The mandatory synthetic gate (11 tests) CAUGHT A REAL BUG before any real data was touched: the variance-ratio estimator divided by q twice (VR ≈ 1/q on a pure random walk). Fixed; all detectors then read 0 on random walks and recover planted effects. expB then ran the pre-specified protocol (hypothesis.md written first): 12 liquid + 30 seed-42 random tickers, Q1 2024, RTH 1min, 47 requests, 795k rows.

Result. Median by staleness tercile (staleness | AC1 | Roll spread | VR30 | SPY-leads-+1min): fresh 0.00 | −0.009 | 1.4bp | 0.97 | +0.005; mid 0.11 | −0.051 | 3.8bp | 0.90 | +0.047; stale 0.69 | −0.232 | 17bp | 0.55 | +0.021. Spearman(staleness, SPY-lead) = +0.43. SPX-vs-SPY: SPY leads by 1min at +0.065. Mega-caps: no measurable bounce (AC1 CI covers 0).

Interpretation. Uncorrected VR/AC1 scans on mid/low-liquidity names are dominated by plumbing, not economics. Nulls usable; both falsification criteria failed to trigger. All Level 0 by construction.

Decision. artifact_taxonomy.md now carries 7 entries with measured magnitudes (T1–T7). Next: expC consumes the bucket-matched bounce null; Phase 1 literature sweep in parallel.

# 2026-08-12 02:45 ET — Phase 1 complete: literature sweep (52 verified sources)

Question. What does the literature establish about Q1-Q3 anomalies, the statistics of not fooling yourself, microstructure artifacts, and costs?

Method. Three parallel verification passes against OpenAlex (every citation confirmed: title, authors, year, venue, DOI; access date 2026-08-12), plus discovery searches for 2005-2025 decay/replication work. Six theme notes written in research/notes/; consolidated bibliography.

Key priors adopted. (i) McLean-Pontiff: -26% OOS, -58% post-publication — the base rate. (ii) Sullivan-Timmermann-White: calendar effects vanish under the Reality Check. (iii) Chordia-Goyal-Saretto/Harvey-Liu-Zhu: t-hurdle >= 3.0 floor, 3.4-3.8 band reported. (iv) Novy-Marx-Velikov + Chen-Velikov: high-turnover (short-horizon) anomalies mostly die at costs (~4bp/month average net). (v) Chordia-Roll-Subrahmanyam: minute-scale inefficiencies arbitraged within 5-60 min already by 2005. (vi) Marquering et al.: turn-of-month was the last calendar survivor (2006) — the single most interesting re-test. (vii) EDGE (Ardia et al. 2024) chosen as primary OHLC spread estimator for expG.

Decision. Error-rate ladder fixed for Phase 9: FDR for scans -> SPA/StepM vs artifact nulls for Level 1 -> DSR with logged trial counts. Next: Phase 2 state-of-the-art map, then research_gaps (Phase 3). In parallel (user request): major web platform upgrade (mobile + comments).

# 2026-08-12 03:30 ET — Phases 2–4 complete: state of the art, 22 hypotheses, candidates selected

Question. Given the verified literature and the measured artifact nulls, which hypotheses deserve prototyping?

Output. state_of_the_art.md (10 anomaly families in the §5 template with epistemic status + methods/arm64 inventory); research_gaps.md (H01–H22, each with a constructable artifact null; MULTIPLE-TESTING BUDGET DECLARED: 22); candidate_ranking.md (10-axis scores).

Selected. C01=H15 intraday-momentum post-2018 decay; C02=H13 turn-of-month 2006–2026; C03=H11+H03 index-artifact decomposition (SPX/SPY staleness + Fisher VR share); C04=H10 crypto-weekend→Monday-gap (novelty pick). Reserve: H09. Controls H14/H20/H21 run inside the micro-experiment pipeline. Selection used priors + expA/expB artifact levels only — no real-data effect peeking.

Decision. Next: expC–expE scans (consuming expB nulls), then expF correction with the declared 22-hypothesis budget. Candidate 04 requires crypto volume-semantics verification first (expA follow-up).

# 2026-08-12 06:40 ET — expC complete: null mis-specification caught, corrected triage = 14 cells

Question. Which reversion cells exceed the bounce null (H01, H02-scan)?

Experiment. expC on TRAIN only (2000-2016; splits frozen in universe.py BEFORE the scan). 354 requests, 10.5M rows, 127 cells, BH-FDR per family.

Result. The pre-specified EDGE+Roll bounce null is MIS-SPECIFIED intraday (predicts AC1 −3..−27, impossible) — the 90 positive-excess "survivors" are artifacts of the null and were DISCARDED. Post-hoc null FIX (documented here per §12; this is a null correction, not a hypothesis expansion; budget stays 22): MA(1)-consistent VR null. Corrected triage: 14 cells with FDR + VR30 excess < −0.05 (JPM 1min 2014-15 −0.243; MSFT 5min 2000-07; XOM/NVDA 1min) + a broad daily 2008-2015 mega-cap/index reversal family (XOM excess_AC1 −0.133 FDR, SPY −0.055 FDR).

Interpretation. H01 CONFIRMED (liquid intraday lag-1 reversion = 0 net of bounce). Decay clause PARTIALLY FALSIFIED (flat 5min, mild 1day decay inside train). Methodological finding adopted: variance-consistency requirement for spread-based nulls (taxonomy T1 amended).

Decision. 14 triage cells + daily-reversal family -> expF/expH. Next: expD lead-lag scan with MA(1)-consistency lesson applied.

# 2026-08-12 07:20 ET — expD complete: lead-lag decay measured on synchronized pairs

Question. Which lead-lag survives synchronization (H07/H08 scan), and do the H09/H11 previews hold?

Experiment. expD, protocol pre-specified: 49 pair-cells, 2 windows, raw-LOCF vs both-fresh, day-block bootstrap, BH-FDR over 98 tests. 198 requests, 8.4M rows.

Result. 2006-2007: real minute-scale diffusion (SPY->XLK +0.148 both-fresh). 2014-2015: collapse to [-0.02, +0.05]; a few tiny FDR survivors — H08's expected-negative clause formally FALSIFIED (recorded). ES->SPY: -0.032 splice-invariant (basis-reversion-like). SPX->SPY: +0.132 both-fresh, artifact share ~0 — content staleness, not print staleness (H11 scan-confirmed). T3 amended: LOCF artifact is non-monotone (inflates mid-stale, dilutes ultra-stale).

Decision. To expF: 2014-15 FDR residuals + ES->SPY + decay curve. Next: expE calendar scan (pre-counted budget), then expF.

# 2026-08-12 07:55 ET — expE complete: the calendar is empty; controls held

Question. Do any of the 8 pre-declared calendar classes (H13/H14/H18) beat the permuted-calendar null on SPY train?

Experiment. expE — budget pre-counted at 8 tests, single declared instrument, within-year permutation null (n=2000, seed 42) with family-wise max-stat, plus the H20 intraday profile measurement. 1 new API request (rest cache-served).

Result. ZERO survivors (family-wise p >= 0.93 everywhere). Monday negative control held (-1.4bp, p .73). Turn-of-month — the 2006-era last survivor — fails (p_marg .24) and decays inside train (+7.9bp -> +1.6bp). Holiday power is low (n=144, bands +/-21bp) — reported as such. H20: volatility U-shape confirmed (6.6/2.4/2.9 bp); spread declines 2.8 -> 1.2bp (L-shape, not U) — taxonomy updated with the measured profile.

Interpretation. STW (2001) reproduced on open data with an honest budget. Candidate 02 (turn-of-month) now carries a dead-on-arrival prior into its validation protocol — the expected atlas outcome is a first-class negative finding.

Decision. Nothing from expE enters the expF pool. Next: expF correction battery over the C/D triage output, with the declared 22-hypothesis budget.

# 2026-08-12 08:40 ET — expF complete: the survival curve, and its methodological headline

Question. What fraction of the searched universe survives honest search correction (charter result-type E)?

Experiment. expF — 372 signed rules from EVERYTHING C/D/E searched, 6 blocks, White RC + Hansen SPA (500 stationary bootstraps, gate-tested)

  • BH-FDR + DSR. 0 network requests — fully served by the frozen cache.

Result. Gross funnel: 372 -> 232 naive (62%) -> 226 FDR (61%) -> 68 SPA step-1 (18%). Best "Sharpes" 10-31 annualized = the §12 red flag. The known SPX->SPY artifact SURVIVES SPA (canary). expE calendar block: nothing survives (tripwire did not fire). Intersection with expC's artifact-adjusted triage: 12/14 cells; plus -L:ES->SPY.

Interpretation. Statistical correction corrects for SEARCH, not MECHANISM: SPA survivors are dominated by bounce harvesting and frictionless timing. Honest validation needs artifact nulls AND search correction AND costs — no substitutions. Added to methodology as an axiom with this experiment as the demonstration.

Decision. Double-filtered pool (12 reversion cells + ES->SPY + expD 2014-15 FDR set) -> expG cost frontier. SPX->SPY routed to candidate 03.

# 2026-08-12 09:10 ET — expG complete: the cost frontier kills the pool

Question. Where does each double-filtered survivor's net effect cross zero (Q5)?

Experiment. expG — pool rebuilt mechanically from committed results (31 rules), net = gross - kappa*(EDGE/2)turnover, kappa in {0,.1,.25,.5, 1,2}, block-bootstrap CIs, breakeven kappa per rule.

Result. Median kappa* = 0.0114 (max 0.28). Survivors: 3 at kappa=0.1, 1 at 0.25 (CKX 1day), 0 at 0.5 and beyond. Zero intraday rules survive kappa=1 (pre-registered falsification did not trigger). ES->SPY kappa* = 0.0028, splice-invariant.

Interpretation. The gross survivors were harvesting the spread they would have to pay — Novy-Marx-Velikov/Chen-Velikov reproduced on open data. Three-layer doctrine complete: artifact nulls (scans) + search correction (expF) + costs (expG), none substitutable.

Decision. expH validation split: CKX 1day (skeptical prior), the daily 2008-15 reversal family (for the record), and the negative finding itself ("nothing intraday survives costs") — candidate for the atlas's first entries.

# 2026-08-12 10:05 ET — expH complete: the ladder closes; first atlas entries

Question. Do the train-split survivors and the negative finding hold on the untouched validation split (2016-2021)?

Experiment. expH — validation opened for the first time (418 requests, 18.8M rows). Machinery imported from committed expC/expD/expG benchmarks.

Result. Negative finding REPLICATES (0 net survivors at kappa=1; only CKX at 0.25). CKX fails its pre-registered two-sub-period clause (2019-21 CI covers 0; kappa* decays 0.445->0.263) — not confirmed, holdout NOT spent. ES->SPY flips sign (+0.003, p=0.68). Daily reversal family: VR30 excess -0.143 -> +0.023 — crisis-regime confirmed. SPX->SPY artifact persists (+0.080): artifacts replicate, "alphas" do not.

Decision. Atlas receives its first entries: F001 (Level 2 negative finding: nothing in the searched universe survives the full ladder) and F002 (Level 2 artifact demonstration: the SPX->SPY lead is content staleness). Holdout stays sealed. Publications tab launched with P001 (Part I, train results); Part II will carry these OOS verdicts.