Pre-registered quantile-regression test of whether Qullamaggie-style volume contraction during a stock's consolidation base raises the upper tail of 20-day forward returns more than it raises the median, after controlling for FF3+UMD factor returns, sector fixed effects, and year fixed effects.
Deliverable: writeup.ipynb at the repo root. Open it and run all cells — every figure, table, and number regenerates from the four committed parquets in data/.
Pre-registered hypothesis: writeup.ipynb §6 (locked 2026-05-03, before any QR fits ran).
python -m venv .venv
.venv/Scripts/activate # Windows; on POSIX use `source .venv/bin/activate`
pip install -r requirements.txtPython ≥ 3.11 required.
Only four parquets are committed under data/, one per analysis-stage output:
m3_setups_with_residuals.parquet— main analysis panel (5,286 setup-rows × M1+M2+M3 columns)m4_results.parquet— OLS + QR coefficient table on the training windowm5_oos_results.parquet— expanding-window walk-forward summarym6_bootstrap.parquet— stationary block bootstrap draws (real + placebo)
data/raw/ is gitignored — it sources Polygon daily bars from a separate breakoutStudyTool pipeline and is not redistributable. Intermediate stage parquets, the FF3+UMD factor panel, the SPY cache, and the yfinance ticker-type cache are also omitted from the committed tree; they regenerate from upstream sources on a full pipeline re-run (M3/M2 download Ken French and SPY automatically; M1's yfinance ticker-type cache is repopulated by src/_fetch_ticker_types.py and src/_fetch_ticker_adr_fields.py).
To verify only the writeup: open writeup.ipynb and Run All. It loads the four committed parquets and regenerates every output inline.
To re-run the full pipeline from scratch: execute the modules in order. Each writes its outputs to data/ and emits a per-stage validation report to reports/ as a side effect (reports/ is gitignored).
python src/m0_audit.py— survivorship + bad-bar audit. Writesdata/m0_audit_summary.json.python src/m1_universe.py— Qullamaggie consolidation-breakout detector. Writesdata/m1_setups.parquet.python src/m2_features.py— per-setup features (vol contraction, ADR, RS-vs-SPY, sector). Writesdata/m2_setups_with_features.parquetand (if absent) cachesdata/spy_daily.parquet.python src/m3_factors.py— FF3+UMD factor panel + 20-day-forward residualization on 2010–2017 training. Writesdata/ff3_umd_daily.parquet,data/m3_setups_with_residuals.parquet.python src/m4_estimation.py— OLS + QR(τ ∈ {0.10, 0.25, 0.50, 0.75, 0.90}) on training. Writesdata/m4_results.parquet.python src/m5_walkforward.py— expanding-window OOS sign-consistency check, 2018–2025. Writesdata/m5_oos_results.parquet.python src/m6_bootstrap.py— stationary block bootstrap CI + placebo (~8 min). Writesdata/m6_bootstrap.parquet.