Linear algebra for quants
A portfolio is a weighted sum of assets, and its risk is a quadratic form in those weights. Once you see that, the whole machinery of portfolio theory — variance, diversification, risk factors — collapses into three objects from linear algebra: a weight vector, a covariance matrix, and its eigenvectors. This chapter builds that vocabulary from the ground up, derives the one formula every optimizer uses, and shows why the eigenvectors of the covariance matrix arethe market’s hidden risk factors.
Forget matrices for a second. You hold three things: some Bitcoin, some Ether, a little gold. Two questions run your book. What did I make today?— add up each holding’s move, weighted by how much of it you own. How risky am I? — that one is subtler, because BTC and ETH tend to crash together, so holding both is not two bets but nearly one, while gold usually zigs when crypto zags and quietly cancels risk. Linear algebra is just the bookkeeping that turns those two questions into a vector (the first) and a matrix sandwiched between two vectors (the second). Everything hard in this chapter is a way of reading that second object — the covariance matrix — correctly.
Vectors: returns and weights#
Take assets. On a given day their returns are just a list of numbers, which we stack into a column vector . How you split your capital across them is a second vector, the weights , where is the fraction of the book in asset . “Fully invested” is the linear constraint that the weights sum to one:
The portfolio’s return for the day is the dot productof the two — each asset’s return scaled by how much you held of it, summed:
The superscript is transpose: it turns the column on its side so the multiplication lines up term-by-term. Everything that follows is built by stacking these vectors into matrices and asking what happens to the dot products.
The covariance matrix Σ#
Return is linear in the weights, so its expectation is trivial: where is the vector of expected returns. Risk is where the structure lives, because it depends on how assets move together. That co-movement is packed into the covariance matrix , an table whose entries are
The diagonal is each asset’s own variance; the off-diagonal is how asset and asset co-vary. Because , the matrix is symmetric: . From a matrix of historical returns (rows = periods, columns = assets), the sample estimate is a single matrix product on the demeaned data:
That is exactly what ek.optimize.sample_cov computes — a demeaned Gram matrix normalised by . It is the maximum-likelihood covariance and it is the raw material for every risk calculation in the rest of Part VI.
import edgekit as ek
# returns: T x N DataFrame (rows = days, columns = assets)
Sigma = ek.optimize.sample_cov(returns) # N x N covariance, ddof=1
Sigma.shape # (N, N)
Sigma.diagonal() # per-asset variances (sigma_i^2)Portfolio variance as a quadratic form#
Here is the formula that motivates the whole chapter. The variance of the portfolio return is the quadratic form
Portfolio return is a weighted sum, . Variance of a sum expands into variances plus every pairwise covariance — this is the bilinearity of covariance, :
The right-hand double sum is, by the definition of matrix multiplication, precisely : multiplying by on the right forms the inner sum over , and the outer forms the sum over . Hence . Why it matters: risk is not the weighted average of individual risks — the cross terms are the whole story. Two volatile assets with negative covariance can combine into a low-variance book; that cancellation, buried in the off-diagonals, is what diversification means mathematically.
Split the double sum into its diagonal and off-diagonal parts to read the diversification directly:
If the assets were uncorrelated the second term vanishes and risk is just the weighted sum of variances. Real assets are correlated, and the sign and size of that second term is what an optimizer is really trading against return. When correlations are positive it inflates risk; when some are negative it deflates it — the free lunch of diversification.
Put real-ish annualised numbers on the desk. Volatilities: , , . Correlations: (crypto moves together), , . Each covariance is , so the matrix is
Now evaluate the quadratic form. The diagonal (“own risk”) contributes ; the off-diagonal (“interaction”) contributes . Add them:
Read the numbers. A trader who ignoredcorrelation would guess the book’s risk was the weighted average of vols, . If the assets were truly uncorrelated the diagonal alone would give . Reality — — sits between: the BTC/ETH correlation is almost the entire interaction term (it alone adds of variance), while gold’s near-zero correlations barely move it. That single off-diagonal cell is why “I hold BTC and ETH” is closer to one bet than two — and why the calm, uncorrelated gold sleeve is doing the real diversification work despite its tiny weight-share of the risk.
Positive semi-definiteness#
A variance can never be negative. Since is a variance for any weights whatsoever, the covariance matrix must satisfy
A symmetric matrix with this property is called positive semi-definite (PSD). It is not a technicality — it is a hard constraint that every valid covariance must obey, and it has three consequences you will keep meeting:
- All eigenvalues are . A negative eigenvalue would let you build a portfolio with negative variance — impossible. (Strictly positive eigenvalues make positive definite and therefore invertible.)
- The inverse can be unstable. A near-zero eigenvalue means is nearly singular, so (which the optimizers of the next chapter need) explodes. This is the numerical face of over-fitting a covariance from too little data.
- Sample estimates can break PSD. When you have fewer observations than assets (), the sample covariance is rank-deficient — it has exact zero eigenvalues and is only semi-definite. That is one of several reasons shrinkage estimators exist.
ek.optimize adds a tiny multiple of the identity () when the condition number blows up. That nudges every eigenvalue up by , restoring a stable, still-PSD matrix without moving a well-behaved one. The principled version of the same idea — Ledoit-Wolf shrinkage — is the subject of the next chapter.The correlation matrix#
Covariance mixes co-movement with scale — a large could just mean two volatile assets. To see the pure relationship, standardise each asset by its own volatility. The result is the correlation matrix :
In matrix form, with the diagonal matrix of volatilities, — a unit-diagonal, symmetric, still-PSD matrix. It is the right object to look at, because every entry is on the same scale. In edgekit, ek.portfolio.correlation takes a dict of strategy R-streams and returns exactly this matrix — the diagnostic you use to check that the sleeves of a book are actually diversifying rather than secretly the same bet.
import edgekit as ek
# books: {"orb": r_series, "sma": r_series, ...} of daily-R Series
rho = ek.portfolio.correlation(books) # unit-diagonal correlation DataFrame
rho.loc["orb", "sma"] # pairwise correlation of two sleeves
Eigenvalues, eigenvectors, and PCA#
A symmetric PSD matrix has a special structure: it can be written entirely in terms of its eigenvectors and eigenvalues. An eigenvector is a direction that merely stretches without rotating, and its eigenvalue is the stretch factor:
The spectral theorem says any symmetric decomposes into an orthonormal set of such eigenvectors, collected as columns of an orthogonal matrix , with eigenvalues on a diagonal matrix :
This is Principal Component Analysis. Each eigenvector — a principal component — is a specific combination of the assets (a synthetic portfolio), and its eigenvalue is the variance of returns along that direction.

Consider the portfolio whose weights are a unit-length eigenvector, with . Its variance is the quadratic form from above; substitute the eigenvector equation :
So the variance of the return along principal component is exactly its eigenvalue. The largest eigenvalue belongs to the highest-variance direction in the whole asset space — no unit-weight portfolio has more variance, which is a one-line consequence of the Rayleigh quotient . Because the eigenvectors are orthogonal, the components are uncorrelated synthetic assets, and the trace identity says the eigenvalues simply repartition the total variance of the market into independent buckets.
The fraction of total variance explained by the first components is the cumulative eigenvalue ratio, and it is the honest answer to “how many independent risks am I holding?”:

Diagonalise the from the scenario above and its three eigenvalues come out roughly , , (they sum to , as the trace identity demands). The top eigenvector is almost entirelya long-BTC/long-ETH combination — that is “crypto beta,” and it alone is of the total variance. The second eigenvector is dominated by gold. The upshot: three tickers, but of your risk lives on one axis — you are running closer to one and a bitindependent bets, not three. That is the number a correlation heatmap cannot tell you but the eigenvalues can, and it is exactly what a risk manager means by “effective breadth.”
Why PCA finds risk factors#
The eigenvectors are not just a numerical convenience — for financial returns they line up with economically meaningful risk factors. When you run PCA on a basket of correlated assets you almost always see the same pattern:
- The first component is “the market.” Its eigenvector has the same sign in every asset — a roughly equal-weight long that goes up when everything goes up. For equities it typically explains the large majority of the variance; it is the systematic beta that no amount of stock-picking diversifies away. This is the linear-algebra shadow of the market factor.
- Later components are style/sector spreads. The second and third components have mixed signs — long one group, short another — and correspond to interpretable tilts (sector, size, value, duration). They are the market-neutral spreads a relative-value trader lives on.
- The tail is noise. The many tiny eigenvalues correspond to idiosyncratic wiggle. A near-zero is precisely the near-singular direction that destabilises — over-fitting risk, made visible.
This is why factor models and PCA are two views of the same object: a factor model says returns are driven by a few common factors , and PCA discovers those factors as the top eigenvectors of without being told what they are. The next chapter takes the complementary route: given a factor you name in advance (the market), regress against it to measure exposure.
| Object | Symbol | Linear-algebra role | edgekit |
|---|---|---|---|
| Weights | Vector, sums to 1 | portfolio weights | |
| Covariance | Symmetric PSD matrix | ek.optimize.sample_cov | |
| Correlation | Standardised Σ, unit diagonal | ek.portfolio.correlation | |
| Portfolio variance | Quadratic form | ek.optimize.portfolio_vol | |
| Risk factors | Eigenvectors / eigenvalues of Σ | PCA (numpy.linalg.eigh) |
Next: we have the covariance matrix and its factors — now we name a factor in advance and measure how much of a return it explains. Regression & factor models.


