fundlab/styletilt.py: 22 style/asset sleeves regressed on excess-of-T-bill
returns (full history + 5y); BIC forward selection identifies the tilt
stack; residual-alpha verdict ('factor exposure, not skill' when t<1.75);
data-driven English commentary with sign-specific phrasing. Rendered as a
'Style tilts' block (factor table + prose) in both the app and the HTML
report. All 24 pre-built + 8 ad-hoc fund reports rebuilt.
Any symbol that stands alone in the Symbol box (not a comma-joined
portfolio component) now gets a full report, built on demand and cached
in reports/report_data_adhoc.json. Rendered at the top of the Fund Lab
Summary as group 'A'; pointer at the top of the page. Rendering logic
extracted into render_fund_report() shared by pre-built and on-demand
entries. ~0.3-0.9 s per new fund after one-time panel warmup; instant
afterwards (memory + disk cache).
- fundlab/narrative.py: data-driven English prose per fund (performance,
drivers tiered by fit, explicit 'what we do NOT know', bottom line)
- fundlab/reportdata.py: static build -> reports/report_data.json
- app.py Fund Lab Summary: at-a-glance table + per-fund expanders
(narrative, equity curve, period table with fund-ref gap, drivers,
reference mix, tax, cluster peers)
- fundlab/report.py: narrative in the HTML report; forward-selected
reference (weak-fit funds anchor to cash); SLEEVE_DESC exposure
explanations
- BUG: mix_series() never applied the betas (reference curves were raw
sleeve sums; JLPSX 'reference' +407% vs fund +123%) - fixed and all
reference curves/tables regenerated
- reports/fund_report.html + report_data.json regenerated