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
--setoverrides - 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
build-universeConstruct point-in-time membership and resolve symbol overrides.ingest-barsDownload minute bars, resumably and under a rate limit;--dry-runplans without fetching.clean-barsClean and calendar-align, streaming rather than loading the whole panel.compute-returnsBuild horizon returns with the configured sort gaps and edge-minute exclusions.run-sortsForm deciles and long-short portfolios at each horizon.bootstrapBlock-bootstrap the headline spreads.fit-decayFit the decay half-life across horizons.cost-overlayApply the cost grid and compute break-even levels.render-reportRender the brief, figures and artifact tables.validate-production-runGate publication; exit non-zero on anything demo-labelled or incomplete.
Reproducibility and validation
validate-production-runchecks 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.