Repository navigation
Every issue of the stabilization milestone is closed: 18 issues through 17 reviewed pull requests (#34–#52), each with a failing test written first, hand-calculated fixtures where numbers are asserted, stated limitations, and green CI on Python 3.12, 3.13, Windows, and the packaging job. The suite grew from 254 to 372 tests.
Breaking changes (0.x)
compare_to_benchmarknow takes thePortfolioand datedPriceSeriesand verifies that every series shares one date grid ("run align() first") instead of accepting two raw equal-length return sequences that could silently produce a nonsense beta (#25).RebalanceRecord.turnoveris renamedtwo_sided_turnover— that is what the formula computes; the cost semantics are unchanged (#31).- Capture ratios are now geometric — each side's returns are compounded before dividing — matching how the engine treats returns everywhere else; pre-0.2.0 figures were arithmetic per-day means (#28).
FrontierPointgainscondition_number,conditioning_warning, andefficientfields (#18, #30).
Validation and honesty
- One shared covariance validation path: symmetry, finiteness, and positive semidefiniteness checked at entry via a single eigendecomposition, with the 2-norm condition number carried on results — solvers refuse above 1e12, warn above 1e8 (#17, #18).
- Booleans and non-finite numbers rejected at every public entry point, including the non-standard JSON NaN/Infinity tokens at spec parse (#20).
- One named near-zero-variance tolerance (
MIN_VOLATILITY = 1e-12) behind every volatility denominator, argued from float64 arithmetic (#26). quantrisk validatenow guarantees runnability: both commands share one feasibility check that runs the evaluation's own code paths, property-tested over a seeded sweep of adversarial specs (#21).- The session model is explicit: each row is one trading session, calendar gaps carry no information and are never rejected, 252 annualizes sessions, weekend dates are legal (#19).
PolicyWindowenforces its look-ahead invariants at construction with precise messages, at no measured cost (#27).- VaR/CVaR conventions derived and pinned: losses positive, Hyndman–Fan type 7 quantile, discrete tail cut at the interpolated boundary — with fixtures where rival textbook conventions demonstrably differ (#29).
- Frontier sweeps label the dominated branch below the minimum-variance return, boundary computed under the sweep's own constraint set (#30).
Robustness and reproducibility
- Monte Carlo draws are processed in fixed 512-run blocks — peak memory ~10 MB instead of >1 GB at the caps — with terminal values proven bit-identical for identical seeds (#22).
- Parametric runs whose value path reaches zero are absorbed at exactly 0.0 and counted in a new
bankruptciesfield; bootstrap runs provably cannot go bankrupt (#23). results.jsonandreport.mdpublish atomically as a pair: any failure restores the output directory to exactly its prior state (#24).- Every results artifact carries a
provenanceblock — SHA-256 of the input files' raw bytes plus the quantrisk, Python, NumPy, and SciPy versions — and the docs explain how to verify a report with it (#32). - CI builds the sdist and wheel, installs them into clean environments, runs the suite against the installed package, and proves the unpacked sdist tests itself with no repo checkout on the path (#33, #44).
All sample data is fictional. Nothing in this project is investment advice.