Commit Graph

2 Commits

Author SHA1 Message Date
9f666538c3 Add CASH axis: money-market/cash-equivalents as a return driver
A fund's yield is a near-constant in return space, so OLS puts it in
the intercept (alpha_ann), not in the shv/bil betas (which only
measure rate-CHANGE sensitivity). Cash funds therefore showed no
dominant driver.

- factors: cash_yield() (shv trailing-1y total return = local
  stand-in for the 13-wk T-bill / 0-3m Treasury index), AXES =
  DRIVERS + ['cash'] (alpha_ann / cash_yield, 1.0 = earns the cash
  rate); a display/clustering axis, not a regressor.
- cluster: cash column in the loading matrix; k-means distances use
  the cash-2x-emphasized matrix (a pure cash fund's level axis was
  otherwise swallowed by the low-exposure cloud); labels use raw
  values; label() cash-aware (0.25 threshold, 1.5x runner-up).
- app: cluster view over AXES with the emphasized distance.

The 331-fund 'no dominant driver' grab-bag now splits into
'cash (yield) +0.64' (n=187, MM + ultra-short) and 'cash (yield)
+1.26' (n=59 pure). 123/123 tests.
2026-08-30 13:27:41 -04:00
f68b239b9a Factor screen (v2, 35 drivers) + return-driver clusters
factors.py: full OLS of all 2,384 funds on a 35-driver basis
(overinclusive, no portfolio-corr screening - corr is a replacement
signal, not a rejection). v1's 21 + lqd/hyg/prefs/emb/tip/shy/vtv/
8 sectors/CTA/commodities. Basis fixes: drop vea/vug (dupes of
efa/qqq), drop finux (TERMINATED 2017 - silently zeroed the
complete-case mask; v1 forward selection never hit this), drop bil
(shv/bil near-null -> offsetting shv+64/bil-54 noise fits),
residualize vblix on ivv+tlt (pure vol axis), ridge 0.02.

cluster.py: hierarchical tree saved but fixed-k cuts degenerate
(most funds are blends -> one 2250-fund blob); k-means++ (deterministic)
is the useful grouping, re-run live in-app for any k.

app: Return-driver clusters expander (k slider 10-60, summary table,
member table sorted by alpha-t). Findings at k=30 in RESEARCH.md.
2026-08-27 08:35:42 -04:00