Honesty doctrine. Every candidate anomaly is an artifact until proven otherwise; in-sample results are never findings; past statistical regularity does not imply future returns. This is research on statistical properties of market data — not investment advice, not a trading system.

Research / research/artifact_taxonomy.md

Artifact taxonomy

reviewed

Artifact taxonomy · created Tue Aug 11 2026 20:00:00 GMT-0400 (heure avancée de l’Est) · updated Tue Aug 11 2026 20:00:00 GMT-0400 (heure avancée de l’Est) · Simon-Pierre Boucher

Artifact taxonomy (living document)#

The catalogue of mechanisms in this specific dataset that manufacture fake anomalies — a primary deliverable (Q4). Every entry: mechanism, detection, measured magnitude on this data, neutralization. Magnitudes from results/expA_data_reality/20260812T054515Z/ and results/expB_artifact_baselines/20260812T055602Z/ (Q1 2024, RTH 1min, pre-specified universe). Detectors validated on synthetic ground truth first (benchmarks/synthetic/test_synthetic_gate.py, 11 tests).

T1 — Bid-ask bounce (Roll)#

  • Mechanism. Trades alternate bid/ask; observed returns gain a negative lag-1 autocovariance (−s²/4) with no economics. Masquerades as mean-reversion (Q1).
  • Detection. Roll implied relative spread 2·√(−autocov1); bounce-implied AC1; excess_reversion() (validation/artifacts.py).
  • Measured. Median AC1 by staleness tercile: −0.009 (fresh) / −0.051 (mid) / −0.232 (stale); Roll spread 1.4 / 3.8 / 17.0 bp. Mega-caps: no measurable bounce (AC1 CI covers 0; Roll undefined ~half the time — positive autocov).
  • Neutralize. Report reversion net of the liquidity-bucket bounce null; never average AC1 across liquidity buckets; treat Roll-undefined as "no bounce measurable", not zero spread.
  • expC amendment (measured). A daily effective spread (EDGE) combined with pure Roll alternation predicts impossible intraday AC1 (−3 to −27): consecutive intraday closes do not flip sides each bar. Spread-based bounce nulls MUST be variance-consistent with the target series; for intraday scans use the MA(1)-consistent VR null (VR_null(q) = 1 + 2·AC1·(1−1/q)) — conservative, absorbs all lag-1 effects.

T2 — Stale prices / missing minutes#

  • Mechanism. Bars exist only where trades occurred (expA: zero zero-volume bars; an illiquid name printed 38 bars/day). LOCF joins add a large mass of zero returns and depress variance-ratio statistics.
  • Detection. staleness_ratio on the 390-min RTH grid.
  • Measured. Staleness up to 0.90 (RITM.B); VR(30) = 0.55 median for the stale tercile — 0.35 extreme — with zero planted economics. 11/42 pre-specified tickers had too little data to analyze at all.
  • Neutralize. Explicit grids with observed-masks (never silent LOCF); liquidity filters pre-specified; VR/AC1 claims benchmarked against the staleness-matched null, not against 1.0.

T3 — Non-synchronous lead-lag (LOCF cross-correlation)#

  • Mechanism. A fresh series LOCF-joined to a stale one appears to LEAD it: the stale print reflects old common information (classic non-synchronous trading bias).
  • Detection. Lagged cross-correlation vs SPY on the LOCF grid; synthetic ground truth: rho=0.7 pair with 30 % observation → spurious +1 lag corr.
  • Measured. SPY "leads" mid-staleness tickers by +0.047 at +1 min (Spearman vs staleness +0.43). SPX-vs-SPY: +0.065 with SPY leading 1 min at 0.965 contemporaneous corr — index prints lag the ETF.
  • Neutralize. Any Q2 lead-lag claim must exceed the staleness-predicted cross-correlation; test on synchronized (both-fresh) subsamples; index series are stale by construction.
  • expD amendments (measured). (i) The artifact is NON-MONOTONE in staleness: LOCF joins inflate leads for mid-stale names (+0.047, expB) but DILUTE them for ultra-stale names (HTD raw +0.048 vs both-fresh +0.073) — naive joins can hide lead-lag as well as manufacture it. (ii) For computed indices, synchronizing on PRINT times removes nothing: SPY leads SPX +0.132 both-fresh (fresh_frac 0.996) — content staleness must be modeled, not print gaps.

T4 — Auction close vs last bar#

  • Mechanism. Daily bars carry the official closing-auction print; 1min bars do not (expA: AAPL 312.41 daily close vs 312.49 last RTH 1min close). Mixing conventions manufactures phantom overnight/close-to-close returns.
  • Measured. 8 bp discrepancy on a calm day for the most liquid stock.
  • Neutralize. Pick ONE close convention per experiment and state it; never compute overnight returns across mixed conventions.

T5 — Rolling adjustment anchor#

  • Mechanism. adj_splitdiv re-bases the whole history to the dataset build date (expA: AAPL 2020-08-31 close = 125.17 adjusted vs 129.04 traded). Adjusted series are not point-in-time stable → silent look-ahead and irreproducibility if the cache is refreshed mid-study.
  • Neutralize. Frozen local cache (hf_client never silently refetches); data-manifest hash in every provenance; intraday work uses within-day returns (adjustment-invariant) or UNADJUSTED plus explicit factors.

T6 — Daily vs intraday volume conventions#

  • Mechanism. Daily volume includes auction/consolidated prints absent from 1min bars (expA: 46.1 M daily vs 34.7 M extended-1min sum vs 25.7 M RTH-1min sum for AAPL on one day — a 1.8× spread across conventions).
  • Neutralize. Volume-based signals pick one convention; never mix daily and intraday volume in one feature.

T7 — Vendor session / timezone semantics#

  • Mechanism. All timestamps are US/Eastern wall-clock without a marker; sessions differ per class (equities 04:00–19:59, SPX prints to 16:20, futures ≈24 h, fx ET-week, crypto 24/7). Cross-asset joins on naive timestamps silently compare different market states.
  • Neutralize. One canonical calendar module (data/calendars.py), explicit session filters per asset class, DST-aware conversions.

T1/T2 intraday profile (measured, expE/H20 — liquid 12, 1min, 2014-2015). Volatility is U-shaped: median |1min return| 6.6 bp at 09:30 → 2.4 bp midday → 2.9 bp at 15:30. The EDGE spread declines monotonically 2.8 → 1.2 bp (an L, not a U). Consequence: intraday return claims concentrated at the open face 2–3× the midday artifact level and double the closing spread — expE/expG must bucket-match their nulls and costs by time of day.

Open items: continuous-futures splice choice (3 variants exposed by the API) as a testable artifact for futures-based hypotheses — expD found the ES→SPY cross-serial effect splice-INVARIANT, so the residual exposure is futures-only level/trend work.