The set-up
Put a fraction of your money in A and the rest, , in B. So means 75% in A and 25% in B, and means everything in A.
Risk is measured by volatility (sigma): how widely a year's return typically swings. Desks write it as a decimal, so 20% is , and . Its square, , is the variance: and .
How the two move together is measured by their correlation (rho), a number from to 1. At 1 they move in perfect step, at in exact opposition, and at 0 they are unrelated. Here : they tend to move the same way, but loosely.
Module 5.5 derives the variance of the portfolio, . Here, take it as given:
Check the ends first. At only the first term is left, : all in A. At only the second is left, : all in B.
Variance is a quadratic in the weight
Multiply out and , then collect the powers of . The result is a quadratic (lesson 1.2.2), with
With the numbers above, , and . A table of the variance, and of the volatility (its square root), shows the shape:
| 0 | 0.25 | 0.5 | 0.75 | 1 | |
|---|---|---|---|---|---|
| variance | 0.09 | 0.0576 | 0.0385 | 0.0326 | 0.04 |
| volatility | 0.30 | 0.2401 | 0.1962 | 0.1806 | 0.20 |
The variance falls and then rises again, so the lowest point lies somewhere near . The table brackets it; the vertex will pin it down.
The parabola opens upwards whenever . Rewritten as , it is a sum of two terms that cannot be negative while . It is 0 only if and the two volatilities are equal.
The minimum-variance weight
The vertex rule from lesson 1.2.2, , gives the weight with the least variance:
Rule: Minimum-variance weight
The share of the money in A that makes the portfolio's variance as small as possible. The rest, , goes in B.
Here : about 74% in A and 26% in B. The lowest variance is , a volatility of about 0.1806. That is lower than A's 0.20 on its own.
The same weight gives the least volatility. A square root keeps the order of positive numbers, so the smallest variance has the smallest square root. Work with the variance, which is the quadratic, and take the square root at the end.
Portfolio variance against the weight in A, with , and . The vertex, at , sits below the dotted level of A on its own.
Try it
The cell computes , and , then the vertex and the volatility there.
The plot shows volatility rather than variance. It is a different curve, not a parabola, but its lowest point is at the same weight.
Try it
Always check a formula a second way. A brute-force search over 100,001 weights finds the same minimum to five decimal places.
How correlation changes the answer
The lower the correlation, the more the two assets offset each other, and the lower the minimum risk.
| lowest volatility | ||
|---|---|---|
| 0.6316 | 0.1192 | |
| 0 | 0.6923 | 0.1664 |
| 0.2 | 0.7358 | 0.1806 |
| 0.5 | 0.8571 | 0.1964 |
| 0.8 | 1.2353 | 0.1952 |
The same two assets at three correlations. Every curve passes through 0.09 at and 0.04 at ; the correlation only bends the middle. At the vertex lies in the shaded band past .
At the formula says to hold 123.5% in A. The extra 23.5% is paid for by a short sale of B: borrowing B's shares and selling them. The weight in B is .
With below , this happens exactly when is above , here . Above that, mixing in B adds risk, and only a short sale of B reduces it.
Many funds may not sell short, so their weight must stay between 0 and 1. With the vertex past 1, the variance falls all the way from to . So the best allowed weight is the end nearest the vertex: , all in A, with volatility 0.20.
Try it with the sliders. Raise past 0.667 and watch the lowest point leave , while the best long-only weight sticks at . Then lower and see the threshold move.
Explore
Move the correlation and the two volatilities. The curve is the variance of the portfolio for each weight in A; the shaded bands need a short sale.
- Minimum-variance weight in A
- 0.7358. 73.6% in A and 26.4% in B, both held long.
- Lowest risk
- variance 0.0326, volatility 0.1806
- Best without short sales
- w = 0.7358, volatility 0.1806
What goes wrong on a desk
The formula is one line, but its inputs come from data and from other people's code. These are the cases that cause trouble.
- Perfect correlation. At the formula gives and a variance of 0: the two assets cancel exactly. At it gives , also with variance 0, by holding 300% in A and in B. Real estimates never reach , so a zero-risk answer means the inputs need checking.
- No single answer. If and , then and . Every weight gives the same variance, and the formula reads . Code must check before dividing.
- Impossible inputs. A correlation of 1.2 cannot occur, but a typo can produce one. Then , the parabola opens downwards, and the vertex is a maximum. The "variance" at even comes out negative, .
- Units. Volatilities typed in percent, 20 and 30, give the same , because only their ratio matters. But the variance then comes out in squared percent, 326.04. Mixing conventions is worse: A's monthly volatility, , with B's annual 0.30 gives instead of 0.7358.
- Estimates move. Volatilities and correlations are estimated from past returns, and they change. The table shows moving from 0.63 to 1.24 as goes from to 0.8. Treat as a guide, not a precise answer.
Try it
min_var returns the vertex and the variance there, rounded. The four lines are the two perfect correlations, percent inputs and mixed monthly and annual inputs.
At the computed variance is about , a rounding error, so after rounding it prints as 0.0.
With many assets, the weights become a vector and the parabola becomes a bowl in many dimensions. Module 4.5 finds its lowest point.
A line in finance: the security market line
Lines from lesson 1.2.1 appear too. The capital asset pricing model (module 4.6) says a stock's expected return is a straight line in its beta . Beta measures how strongly the stock moves with the whole market: 1 means in step with it, 2 twice as strongly.
Here means "expected value", so is the stock's expected yearly return and the market's. is the risk-free rate, the return on a safe government bill.
The intercept is : the expected return at . The slope is the market's extra return over , in return per unit of beta. With and , the line is .
- A stock with should return 10%, one with should return 7%, and one with returns the market's 8%.
- A negative beta is allowed. A stock with tends to rise when the market falls, which works like insurance. The line asks only 0.5% of it, below the risk-free rate.
A stock's distance above or below the line is its alpha. A stock with expected to return 6% sits 1 point below the 7% the line asks: an alpha of . Going the other way, gives , the beta that a 9% expected return implies.
Try it
sml is the line . The loop prints the expected return for five betas.
The last two lines are the alpha of the 6% stock and the beta implied by 9%, solved as in lesson 1.2.1.
The minimum-variance portfolio
Write three functions.
portfolio_vol(w, sA, sB, rho)returns the volatility (the square root of the variance formula above) with weightwin A. It should work whenwis a NumPy array.min_variance_weight(sA, sB, rho)returns . It raisesValueErrorwhenrhois outside , and when , because then every weight gives the same variance.long_only_weight(sA, sB, rho)returns the best weight when neither asset may be sold short: moved to 0 or 1 if it falls outside that range.
The tests compare your weight with a brute-force search, as in the cell above, and try the bad inputs from the desk section.
See the tests
import numpy as np
def test_all_in_one_asset():
"""With all the money in A, the volatility is A's own, 0.20"""
expect_close(portfolio_vol(1.0, 0.20, 0.30, 0.2), 0.20, what="portfolio_vol(1, 0.20, 0.30, 0.2)")
def test_vol_array():
"""portfolio_vol works on an array of weights"""
w = np.array([0.0, 0.5, 1.0])
expected = np.sqrt(w**2 * 0.04 + (1 - w)**2 * 0.09 + 2 * w * (1 - w) * 0.2 * 0.06)
expect_close(portfolio_vol(w, 0.20, 0.30, 0.2), expected, what="portfolio_vol at w = 0, 0.5, 1")
def test_equal_assets():
"""Equal volatilities and zero correlation: split evenly"""
expect_close(min_variance_weight(0.25, 0.25, 0.0), 0.5, what="min_variance_weight(0.25, 0.25, 0)")
def test_matches_brute_force():
"""The weight matches a brute-force search over 100,001 weights"""
w = np.linspace(0, 1, 100_001)
best = w[np.argmin(w**2 * 0.04 + (1 - w)**2 * 0.09 + 2 * w * (1 - w) * 0.2 * 0.06)]
expect_close(min_variance_weight(0.20, 0.30, 0.2), best, what="min_variance_weight(0.20, 0.30, 0.2)", rel=1e-4)
def test_negative_correlation():
"""Negative correlation: the minimum risk is far below either asset's"""
w = min_variance_weight(0.20, 0.30, -0.5)
vol = portfolio_vol(w, 0.20, 0.30, -0.5)
assert vol < 0.15, f"expected a minimum volatility below 0.15, got {vol}"
def _raises_value_error(fn, *args):
try:
fn(*args)
except ValueError:
return True
return False
def test_impossible_correlation():
"""A correlation above 1 raises ValueError"""
assert _raises_value_error(min_variance_weight, 0.20, 0.30, 1.2), "min_variance_weight(0.20, 0.30, 1.2) should raise ValueError"
def test_no_single_best_weight():
"""Equal volatilities with correlation 1 raise ValueError: every weight gives the same variance"""
assert _raises_value_error(min_variance_weight, 0.25, 0.25, 1.0), "min_variance_weight(0.25, 0.25, 1.0) should raise ValueError"
def test_long_only_inside():
"""Long-only, ρ = 0.2: the vertex is already between 0 and 1, so it is kept"""
expect_close(long_only_weight(0.20, 0.30, 0.2), 0.156 / 0.212, what="long_only_weight(0.20, 0.30, 0.2)")
def test_long_only_clips_high():
"""Long-only, ρ = 0.8: the vertex is past 1, so the answer is 1 (all in A)"""
expect_close(long_only_weight(0.20, 0.30, 0.8), 1.0, what="long_only_weight(0.20, 0.30, 0.8)")
def test_long_only_clips_low():
"""Long-only, with A the riskier asset and ρ = 0.8: the vertex is below 0, so the answer is 0"""
expect_close(long_only_weight(0.30, 0.20, 0.8), 0.0, what="long_only_weight(0.30, 0.20, 0.8)")
Summary card
- With weight in A, portfolio variance is a quadratic in . It opens upwards, because is positive unless and .
- Its vertex is the minimum-variance weight . The same weight minimises volatility.
- Mixing in a riskier asset can lower risk; the lower the correlation, the larger the benefit.
- (a short sale of B) when . Without short sales, take the end of nearest the vertex.
- Check inputs: , , and both volatilities in the same units.
- The security market line has intercept and slope the market's extra return. Alpha is the distance above the line.