Spectrum
How λ₁ is computed, why it is the right thing to buy, and what the weights mean.
The fee matrix
Let F be the hours-by-pools matrix whose entry F[t, i] is the fee, in ETH, that accrued to pool i's position during hour t: the pool's volume in that hour times its fee tier, converted at the ETH price. Today that matrix is 168 rows by 14 columns, across 4 chains.
λ₁ in four lines
- Build F from the last 168 hours of fees.
- Standardise each column so a large pool does not masquerade as a correlated one: Z = (F − μ) / σ.
- Take Σ = ZᵀZ / (n − 1) and its top eigenpair by power iteration with deflation. λ₁ is the eigenvalue, v₁ the eigenvector.
- Weights w = max(v₁, 0) normalised to sum to one. Negative loadings get zero, never a short.
Right now λ₁ = 3.10 and explains 22.0% of the variance across the 14 eligible streams. λ₂ explains 14.4%, λ₃ 9.9%. A high first number is the point: it means one factor moves every venue on every chain, and that factor is purchasable.
The implementation is about a hundred lines of dependency-free TypeScript in lib/pca.ts, and it runs identically in the browser and on the server.
Reading the weights
A loading is not a prediction about a venue. It says how much of that pool's fee flow moves with ZEC as a whole rather than on its own. A pool that earns well but only when its own chain is awake gets a low weight even if its absolute fees are large, because the vault is not buying that idiosyncratic risk.
Weights are recomputed each epoch and published at /api/eigen. They decide where newly harvested ETH goes when the vault buys more rights, not what it already owns.
The current basket
The live version, with depth, age and hourly sparklines, is on the app page. The raw vectors are at /api/eigen.