Research

The math behind a sparse, fully-invested, long-only index tracker

We solve a high-dimensional convex problem with non-negativity and simplex constraints via a custom ADMM splitting. λ controls the bias-variance trade-off between tracking accuracy and portfolio sparsity.

The optimisation problem

minwRp  12Xwy22+λw1s.t.w0,  1w=1\min_{w \in \mathbb{R}^p}\;\tfrac{1}{2}\|Xw - y\|_2^2 + \lambda\|w\|_1 \quad \text{s.t.}\quad w \ge 0,\; \mathbf{1}^\top w = 1

XX is an n×pn \times p matrix of constituent returns, yy the index return, ww the desired sparse, simplex-constrained portfolio weights.

L1 vs L2 — why corners give sparsity

The L1 ball's vertices align with coordinate axes — so the constraint hyperplane y=Xwy=Xw almost surely touches it at a vertex (sparse). The L2 ball is rotationally symmetric and has no such vertices.

L1 ball (sparse)L2 bally = Xw constraint

ADMM updates (the three steps)

wk+1=(XX+ρI)1(Xy+ρ(zkuk))w^{k+1} = (X^\top X + \rho I)^{-1}\bigl(X^\top y + \rho(z^k - u^k)\bigr)
zk+1=prox(λ/ρ)1,+ ⁣(wk+1+uk)z^{k+1} = \mathrm{prox}_{(\lambda/\rho)\|\cdot\|_1, +}\!\bigl(w^{k+1} + u^k\bigr)
uk+1=uk+wk+1zk+1u^{k+1} = u^k + w^{k+1} - z^{k+1}

We Cholesky-factorise XX+ρIX^\top X + \rho I once per ρ-update, so each iteration costs O(p2)O(p^2) instead of O(p3)O(p^3).

Pick your λ — interactive

Slide to see the bias–variance trade-off live: tighter regularisation (right) → fewer stocks → higher tracking error.

Demo data — when running against a live API, switching to /api/proxy/api/v1/lambda-path repaints the chart.

Convergence (real residuals)

Primal and dual residuals from a real synthetic 100×300 ADMM solve. Decay is sub-linear at the start, geometric near the optimum (Boyd §3.4).