Welcome back. Previously, we derived the global minimum-variance portfolio,
which uses the covariance matrix alone and is constrained to be fully invested in risky assets. We now introduce expected excess returns and a risk-aversion parameter. This produces a different object: an unconstrained mean-variance allocation, whose total risky exposure is chosen rather than fixed.
By the end of this lesson, you will be able to derive and compute
for a specified risk-aversion coefficient , and interpret what the resulting weights mean operationally.
The mean-variance utility problem
Let:
- be the vector of risky-asset returns over one period;
- be the risk-free return over that period;
- be the vector of excess returns;
- be the vector of expected excess returns;
- be the covariance matrix;
- be the vector of allocations to risky assets.
The portfolio’s expected excess return and variance are
The standard mean-variance utility objective is
where is the risk-aversion coefficient.
The two terms have a direct interpretation:
- rewards expected excess return.
- penalizes variance.
- Larger means variance is penalized more strongly, so the optimizer takes less risky exposure.
Here, “unconstrained” has a precise meaning: we impose no full-investment constraint such as
and no long-only or position-limit constraints. The risky weights can sum to less than, equal to, or greater than one.
When a risk-free asset is available, the residual cash allocation is
Thus, if the risky weights sum to , the investor puts in the risk-free asset. If they sum to , the investor borrows at the risk-free rate to lever the risky portfolio.
This is fundamentally different from the GMVP problem. The GMVP fixed total risky investment at ; this utility problem lets risk aversion determine the amount of capital exposed to the risky assets.
Portfolio Optimization: Mean-Variance Optimization and the Critical Line Algorithm.
Watch “Portfolio Optimization: Mean-Variance Optimization and the Critical Line Algorithm” by Hudson & Thames for a concise intuition about the return-minus-variance-penalty objective. The speaker uses \lambda rather than \gamma for the risk-aversion coefficient.
Watch utility optimization. Focus on how a higher risk-aversion coefficient increases the penalty assigned to portfolio variance; the formal derivation below makes that intuition exact.
Deriving the unconstrained optimal weights
Assume is symmetric positive definite. Then the variance term is strictly convex, so the utility function is strictly concave and has a unique maximizer.
Start from
Differentiate with respect to the weight vector:
At the optimum, the gradient is zero:
Therefore,
Multiplying by gives
This is the unconstrained mean-variance portfolio.
The first-order condition can also be read economically:
At the optimum, each asset’s expected excess return is balanced against its covariance contribution to portfolio risk, scaled by risk aversion. A high expected return alone does not guarantee a high allocation: the asset’s covariance with the whole portfolio matters.
Why this stationary point is the maximum
Define
Completing the square yields
Because is positive definite,
with equality only when . The first term is therefore never positive, establishing that uniquely maximizes utility.
Risk aversion changes scale, not the risky direction
Define the unscaled risky direction
Then
For fixed and , changing multiplies every risky position by the same scalar. It does not alter the relative composition of the risky sleeve.
If doubles, then
Consequently:
while
Expected excess return therefore declines in proportion to , but variance declines in proportion to .
A useful implication is that the Sharpe ratio of this risky direction does not depend on :
Risk aversion selects how much of this efficient risky portfolio to hold, with the remainder allocated to the risk-free asset.

One boundary case deserves care. With , the problem becomes
If any positive-expected-excess-return direction exists and there are no constraints, the objective is unbounded: the optimizer would take arbitrarily large exposure. Thus , or practical portfolio constraints, are necessary for a finite solution.
Also, do not take the unconstrained weights and normalize them to sum to one as a general fix. Normalization changes the optimization problem: it removes the risk-free allocation decision and no longer corresponds to the specified value of .
Worked two-asset calculation
Use the covariance matrix from the previous lesson, now together with annual expected excess returns:
Suppose the investor has
The optimal risky allocation is
So the investor allocates approximately:
| Position | Weight |
|---|---|
| Asset 1 | |
| Asset 2 | |
| Risk-free asset |
The risky weights sum to
The negative risk-free weight means borrowing at the risk-free rate to finance a allocation to the risky sleeve.
The portfolio’s expected excess return is
or about annually. Its variance is
so its volatility is approximately
If instead , all risky allocations halve:
The investor now allocates roughly to the risk-free asset. The risky sleeve has the same relative composition, but the total amount of risk taken is lower.
Reliable Python implementation
As with the GMVP, use a linear solve rather than explicitly constructing .
import numpy as np
def mean_variance_weights(excess_mu, cov, gamma):
"""
Unconstrained mean-variance risky-asset weights.
Parameters
----------
excess_mu : array-like, shape (n_assets,)
Expected excess returns over the same horizon as `cov`.
cov : array-like, shape (n_assets, n_assets)
Positive-definite covariance matrix.
gamma : float
Positive mean-variance risk-aversion coefficient.
Returns
-------
w_risky : ndarray, shape (n_assets,)
Risky-asset weights. Their sum need not equal one.
"""
excess_mu = np.asarray(excess_mu, dtype=float)
cov = np.asarray(cov, dtype=float)
if gamma <= 0:
raise ValueError("gamma must be strictly positive.")
if cov.shape != (len(excess_mu), len(excess_mu)):
raise ValueError("cov must be square and match excess_mu.")
# Solves (gamma * Sigma) w = mu without explicitly inverting Sigma
return np.linalg.solve(gamma * cov, excess_mu)
cov = np.array([
[0.0225, 0.0075],
[0.0075, 0.0625]
])
mu_excess = np.array([0.06, 0.10])
gamma = 3.0
w_risky = mean_variance_weights(mu_excess, cov, gamma)
w_cash = 1.0 - w_risky.sum()
expected_excess_return = w_risky @ mu_excess
variance = w_risky @ cov @ w_risky
volatility = np.sqrt(variance)
print("Risky weights:", w_risky)
print("Risky-weight sum:", w_risky.sum())
print("Implied cash weight:", w_cash)
print("Expected excess return:", expected_excess_return)
print("Volatility:", volatility)
# First-order-condition check: gamma * Sigma * w = mu
print("FOC holds:", np.allclose(gamma * cov @ w_risky, mu_excess))
Expected output, up to rounding:
Risky weights: [0.74074074 0.44444444]
Risky-weight sum: 1.1851851851851851
Implied cash weight: -0.18518518518518512
Expected excess return: 0.08888888888888889
Volatility: 0.17213259316477408
FOC holds: True
In a real implementation, keep several distinctions explicit:
- Estimate as expected excess returns, not raw returns, when interpreting the residual as a risk-free allocation.
- Use a covariance matrix estimated over the same horizon as .
- Do not interpret independently of the return horizon and units used in estimation.
- Treat extreme long-short positions as an output to diagnose, not necessarily a trade list to implement.
Why this matters for random-matrix portfolio methods
The mean-variance solution depends on two estimated quantities:
Thus it inherits instability from both estimated expected returns and the inverse sample covariance matrix.
The covariance component has the spectral representation
where and are sample eigenvalues and eigenvectors. Small sample eigenvalues enter through , potentially producing large and unstable portfolio tilts.
Random matrix theory will help us address the covariance part of that issue. It cannot, by itself, make expected-return estimates reliable; mean estimation is often an even more severe practical problem.
Key takeaways
- The unconstrained mean-variance problem is
- With and positive-definite , its unique solution is
- The weights refer to the risky sleeve. Their sum need not equal one; the remaining allocation is cash or borrowing at the risk-free rate.
- Raising proportionally reduces every risky position while preserving the risky sleeve’s direction.
- In code, compute weights with
np.linalg.solve(gamma * cov, excess_mu), not an explicit matrix inverse. - The same inverse-covariance sensitivity seen in the GMVP is present here, now combined with uncertainty in expected-return estimates.
Next, we will examine why covariance inversion specifically amplifies estimation error in low-variance sample-eigenvector directions.