Software companion

Cross-Sectional Intraday Reversal at Multiple Horizons

Overview

Two risks dominate this study — survivorship bias in the universe and transaction costs in the result — and the software is shaped around keeping either from being papered over. Universe membership is point-in-time by contract: the production configuration requires a real monthly top-500 membership file, and the naive current-top-500 list is accepted only as a labelled survivorship appendix.

The second shape comes from scale. A full 2018–2025 top-500 minute-bar download runs for many hours against free-tier APIs, so ingestion is checkpointed, rate-limited, retried with backoff and capped per run, and every provider call is logged. ingest-bars --dry-run writes the planned calls without fetching, so a long download is inspected before it starts rather than after it fails.

Implementation

Core libraries
pandas, pyarrow, NumPy, SciPy, PyYAML, Jinja2, Matplotlib
Vendors
Polygon and Alpaca behind one vendor interface, plus a synthetic fixture vendor for offline runs
Analysis grid
5, 30 and 60-minute horizons, decile sorts with configurable sort gaps, and configured open and close minutes excluded from the headline
Configuration
A default YAML plus fixture, smoke and local configurations, with dotted --set overrides
Tests
19 modules, including a fixture integration pipeline and a golden report-HTML test
Scale note
A full production download runs to tens or hundreds of gigabytes depending on vendor coverage and retry history

Components

src/universe/
Point-in-time membership, the naive current-list comparator, and symbol and corporate-action overrides
src/data/vendors/
Polygon, Alpaca and fixture vendors behind one interface
src/data/ingest.py
Checkpointed, rate-limited, resumable bar ingestion with sidecar provenance and provider query logs
src/data/clean_bars.py
Streaming cleaning and the session calendar rules
src/analysis/returns.py, sorts.py
Horizon returns and the decile sorts
src/analysis/bootstrap.py
Block-bootstrap confidence intervals that respect intraday dependence
src/analysis/decay.py
Decay half-life fitting across horizons
src/analysis/costs.py
Turnover, the cost grid, and break-even cost levels
src/analysis/neutralization.py
Microstructure and sector controls
src/data/events.py
The optional earnings calendar behind the included/excluded sensitivity
src/validation.py
The publication gate behind validate-production-run
src/utils/manifest.py, repro.py
The run manifest and the determinism helpers

Stages

  1. build-universe Construct point-in-time membership and resolve symbol overrides.
  2. ingest-bars Download minute bars, resumably and under a rate limit; --dry-run plans without fetching.
  3. clean-bars Clean and calendar-align, streaming rather than loading the whole panel.
  4. compute-returns Build horizon returns with the configured sort gaps and edge-minute exclusions.
  5. run-sorts Form deciles and long-short portfolios at each horizon.
  6. bootstrap Block-bootstrap the headline spreads.
  7. fit-decay Fit the decay half-life across horizons.
  8. cost-overlay Apply the cost grid and compute break-even levels.
  9. render-report Render the brief, figures and artifact tables.
  10. validate-production-run Gate publication; exit non-zero on anything demo-labelled or incomplete.

Reproducibility and validation

  • validate-production-run checks required artifacts, report sections, placeholder-free headline text, point-in-time membership presence, demo-mode guards, and demo or smoke labels in the report header — and is expected to exit non-zero on fixture output.
  • The fixture path is explicitly synthetic and marked as such; demo results cannot be promoted to a headline because the gate refuses them.
  • A one-symbol-week credential smoke run is the documented step before any full download, so a vendor problem surfaces in minutes rather than hours.
  • A golden test pins the rendered report HTML, so a change in figures or tables has to be acknowledged rather than absorbed.
  • The limits are recorded in the repository, not only in the write-up: the spread proxy is bar-derived rather than quote-derived, and the cost overlay is a round-trip turnover assumption, not an execution simulation.

Availability

Not publicly released. Running it requires a point-in-time membership file and a Polygon or Alpaca key, and the minute-bar panel it produces is vendor-licensed and far too large to publish. The fixture vendor is in the repository so the pipeline can be exercised without either.

Companion research

A statistically real effect with a break-even cost of a quarter of a basis point, and a bid–ask-bounce artefact at the shortest horizon.

Read the research report