Linear Algebra for Quantitative Finance › Systems of Linear Equations
Quantitative FinanceAll chapters Linear Algebra for Quantitative Finance › Systems of Linear EquationsOne section · Sections in this chapter4 / 9 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
Many financial problems involve systems of linear equations. Hedge construction, factor-exposure matching, and related tasks can often be formulated as for unknown , although practical versions may add constraints, approximation, or optimization.
Why is this formulation so ubiquitous? Because linear systems capture the essence of constraints and requirements. In finance, we often face situations where multiple conditions must hold simultaneously. A hedge must neutralize exposure to several risk factors at once, a replicating portfolio must match the payoffs of a target in multiple scenarios, and factor loadings must explain returns across many time periods. Each condition contributes one equation, and the unknowns are the positions or weights we need to determine. Linear algebra provides systematic machinery for finding solutions when they exist and for characterizing what's possible when they don't.
The General Problem
A system of linear equations has the form:
where:
- : the coefficient in equation for unknown
- : the -th unknown variable we're solving for
- : the right-hand side constant of equation
- : the number of equations
- : the number of unknowns
In matrix form: , where is , is , and is .
The matrix encodes the structure of the problem: how each unknown contributes to each equation. Finding means finding the combination of unknowns that simultaneously satisfies all constraints. In financial applications, often represents sensitivities (like Greeks or factor exposures), represents positions or weights we're solving for, and represents target values we want to achieve.
The geometry of linear systems provides useful intuition. Each equation with at least one nonzero coefficient defines a hyperplane in the space of unknowns (a line in 2D, a plane in 3D, and so on). Solving the system means finding the point (or points, or nothing at all) where all these hyperplanes intersect. When there are exactly as many independent equations as unknowns, and the equations aren't contradictory, the hyperplanes intersect at a single point, giving the unique solution.
Matrix Inverses and Solving Square Systems
When is square () and invertible, the solution is . The inverse satisfies .
The inverse matrix "undoes" the transformation represented by . If transforms inputs to outputs, then transforms outputs back to inputs. In the context of our linear system, we know the outputs (, the targets we want to achieve) and need to find the inputs (, the positions that achieve those targets). Multiplying by the inverse reverses the process, revealing the required inputs.
A square matrix is invertible (or non-singular) when its determinant is non-zero, equivalently when its rows (or columns) are linearly independent. An invertible coefficient matrix gives a unique solution for every right-hand side . Redundancy is a property of the coefficient rows, while consistency or contradiction depends on both and .
In numerical work, solve directly rather than forming explicitly. A solver can use an appropriate factorization without forming the full inverse. For a single right-hand side, explicitly forming the inverse generally adds computation and can introduce additional rounding error. Rank and condition-number checks are still necessary when the system may be singular or ill-conditioned.
Application: Factor Replication
Consider replicating a target portfolio's factor exposures using available assets. Suppose you have three assets with known exposures to two factors (market and size), and you want to construct a portfolio with specific target exposures:
# Factor exposures: rows are assets, columns are factors (market, size)
factor_exposures = np.array(
[
[1.2, 0.8], # Asset 1: high market beta, positive size exposure
[0.8, -0.3], # Asset 2: moderate market beta, negative size exposure
[1.0, 0.2], # Asset 3: market beta 1.0, small positive size exposure
]
)
# Target exposures: we want these factor loadings
target_exposure = np.array([1.0, 0.0]) # Market beta of 1, size-neutral
# We have 3 assets and 2 constraints, so we need an additional constraint
# Add constraint: weights sum to 1 (fully invested)
A = np.vstack([factor_exposures.T, np.ones(3)])
b = np.append(target_exposure, 1.0)Factor exposure matrix (assets × factors): [[ 1.2 0.8] [ 0.8 -0.3] [ 1. 0.2]] Target factor exposures: [1. 0.] Additional constraint: weights sum to 1 Augmented system A: [[ 1.2 0.8 1. ] [ 0.8 -0.3 0.2] [ 1. 1. 1. ]] Target vector b: [1. 0. 1.]
We have 3 unknowns (weights) and 3 equations (2 factor constraints + 1 budget constraint). Let's solve:
# Solve the system
weights = np.linalg.solve(A, b)
# Verify the solution
achieved_exposures = factor_exposures.T @ weights
weight_sum = np.sum(weights)Solution weights: [-2. -2. 5.] Verification: Factor exposures achieved: [ 1.00000000e+00 -2.99760217e-16] Weight sum: 1.000000 Interpretation: Asset 1: -200.00% of portfolio Asset 2: -200.00% of portfolio Asset 3: +500.00% of portfolio
The solution tells us exactly how to combine the three assets to achieve our target factor profile: market beta of 1 with zero size exposure, while being net fully invested. Here the weights are -200%, -200%, and +500%, so the exact match requires short positions and 900% gross exposure. In practice, leverage or short-sale limits can make the exact system infeasible; constrained optimization or regularized least squares can then trade replication error against implementability.
Application: Delta Hedging
In derivatives trading, you often need to hedge exposure to multiple risk factors. Suppose you hold a portfolio of options and want to eliminate its current modeled sensitivity to the underlying price (delta) and volatility (vega). You have two hedging instruments available. Here delta is the change in dollar value per one-dollar underlying-price change, and vega is the change in dollar value per one-percentage-point implied-volatility change. The option column refers to one modeled option unit, not an exchange contract; portfolio and instrument sensitivities use the same units. Actual contract multipliers must be applied before constructing a hedge matrix.
# Current portfolio Greeks (what we need to hedge)
portfolio_delta = 150 # Long 150 deltas
portfolio_vega = -2000 # Short 2000 vegas
# Available hedging instruments
# Instrument 1: Stock (delta=1, vega=0)
# Instrument 2: One modeled ATM option unit (delta=0.5, vega=100)
# Vega values are dollars per one-percentage-point implied-volatility change
hedge_matrix = np.array(
[
[1.0, 0.5], # Delta of each instrument
[0.0, 100.0], # Vega of each instrument
]
)
# Target: neutralize the portfolio Greeks
target = np.array([-portfolio_delta, -portfolio_vega])
# Solve for hedge quantities
hedge_quantities = np.linalg.solve(hedge_matrix, target)Portfolio Greeks to hedge: Delta: +150 Vega: -2000 Hedging instruments (Delta, Vega): Stock: (1, 0) ATM Option: (0.5, 100) Required hedge quantities: Stock: -160 shares Options: +20 modeled option units Resulting portfolio Greeks: Delta: 0.00 Vega: 0.00
In this illustrative calculation, shorting 160 shares of stock and buying 20 modeled option units neutralizes both delta and vega at the stated sensitivities. Other risks and later changes in those sensitivities remain.
Least Squares: Overdetermined Systems
When we have more equations than unknowns (), the system is overdetermined and typically has no exact solution. This happens often in finance. We have many data points (days of returns) but few parameters to estimate (factor exposures).
The least squares solution minimizes the sum of squared residuals:
where:
- : the least squares estimate of
- : the squared L2 norm (sum of squared elements)
- : the residual vector (observed minus fitted)
The solution is given by the normal equations (assuming is invertible):
where:
- : the Gram matrix of the explanatory-variable columns, whose entries are their pairwise inner products
- : a vector containing each explanatory-variable column's inner product with the target vector
Differentiating the squared residual norm gives the first-order condition , or . When the Gram matrix is invertible, solving these normal equations yields the displayed formula. The Gram matrix captures column scale and non-orthogonality; it is not generally a correlation matrix, and its inverse is not a literal correction for "double-counting."
When is invertible, the matrix is the Moore-Penrose pseudoinverse of .
The formula describes the mathematical solution, not a recommended floating-point algorithm. For a full-column-rank matrix, forming squares its 2-norm condition number and can obscure weak directions numerically. Prefer a QR- or SVD-based least-squares algorithm. The example below calls np.linalg.lstsq directly rather than manually forming and inverting the Gram matrix.
Intuitively, least squares finds the that makes as close as possible to in Euclidean distance. The residual vector is orthogonal to the column space of . It is the component not represented by the chosen explanatory-variable columns; changing those columns or the model form can change the residual.
This geometric picture explains why least squares produces the best fit within the chosen column space. Among all possible values of , the least squares solution generates an that is the orthogonal projection of onto the subspace spanned by the columns of . Orthogonal projection onto a subspace always yields the closest point in that subspace. The residual is therefore the in-sample component unexplained by this span. It may contain noise, measurement error, omitted predictors, or misspecification; the projection geometry alone does not identify irreducible statistical error.
This is exactly what ordinary least-squares linear regression computes.
# Estimate factor exposures from return data
# We have many days of returns (observations) and want to find factor betas
np.random.seed(123)
n_days = 100
# True factor betas we're trying to discover
true_betas = np.array([1.2, -0.3]) # Market beta, size beta
# Simulated factor returns
market_returns = np.random.normal(0.0005, 0.01, n_days)
size_returns = np.random.normal(0.0001, 0.008, n_days)
# Factor matrix: each row is a day, each column is a factor
factor_matrix = np.column_stack([market_returns, size_returns])
# Stock returns = factor exposures × factor returns + noise
noise = np.random.normal(0, 0.005, n_days)
stock_returns = factor_matrix @ true_betas + noise
# Estimate betas via least squares
estimated_betas = np.linalg.lstsq(factor_matrix, stock_returns, rcond=None)[0]True factor betas: [ 1.2 -0.3] Estimated betas: [ 1.1715 -0.2855] Estimation error: Market beta error: -0.0285 Size beta error: +0.0145

This fit has no intercept: its only predictors are the two factor-return columns. The plot reports uncentered , where is the simulated stock return and SSE is the sum of squared residuals. This measures improvement over predicting zero return, rather than the mean-return baseline used in centered . The denominator must be nonzero.
The least squares estimates are close to the true values in this seeded simulation, with small errors due to the noise in returns. More observations can support consistency when the model is correctly specified, the limiting regressor second-moment matrix has full rank, and average regressor-error products converge to zero. Exogenous noise with stable finite moments also needs an appropriate sampling condition, such as independence or suitable weak dependence, to establish that convergence; more data alone does not guarantee consistency.