Skip to content

How much risk diversification removes

Course exercise 134 · Part II

Problem

With weekly returns of 221 stocks of the Italian market (MIBTEL), build equally weighted portfolios of the first \(k\) stocks, for \(k = 1, \dots, 221\), and plot their variance against \(k\). Compare it with the level that diversification cannot go below. This is Fama's classic experiment.

Method

For an equally weighted portfolio of \(k\) assets, the variance splits into an average variance term and an average covariance term:

\[ \sigma^2_{EW}(k) = \frac{1}{k}\,\bar{\sigma}^2 + \frac{k-1}{k}\,\bar{\sigma}_{ij} \;\xrightarrow{\,k \to \infty\,}\; \bar{\sigma}_{ij} \]

The first term vanishes as \(k\) grows; the average covariance \(\bar{\sigma}_{ij}\) remains. It is computed as the sum of the off-diagonal elements of \(\Sigma\) divided by their number, \(n^2 - n\).

Code

clear all, clc

%% 1

A = readtable("weekly_MIBTEL_price_time.txt");
time = A{:, 1};
P = A{:, 2:end};

%% 2

RR = diff(P) ./ P(1:end-1, :);
[T, n] = size(RR);
Sigma = cov(RR);

%% 3

var_EW = NaN(1, n);

for k = 1:n
    x_EW = ones(k, 1) / k; % weights
    var_EW(k) = x_EW' * Sigma(1:k, 1:k) * x_EW; % portfolio variance
end

Sigma2_C = (sum(Sigma(:)) - sum(diag(Sigma))) / (n^2 - n);

%% 4

figure(1)
hold on
plot(1:n, var_EW, LineWidth=2)
plot(1:n, ones(1, n) * Sigma2_C, LineWidth=2)
xlabel('n. of assets')
ylabel('Variance')
title("Fama's Experiment")
import numpy as np
import matplotlib.pyplot as plt

# %% 1
A = np.loadtxt('weekly_MIBTEL_price_time.txt')
time = A[:, 0]
P = A[:, 1:]

# %% 2
RR = np.diff(P, axis=0) / P[:-1, :]
T, n = RR.shape
Sigma = np.cov(RR, rowvar=False)

# %% 3
var_EW = np.zeros(n)

for k in range(1, n + 1):               # k = number of stocks in the portfolio, 1..n
    x_EW = np.ones(k) / k               # weights
    var_EW[k-1] = x_EW @ Sigma[:k, :k] @ x_EW   # MATLAB: x_EW' * Sigma(1:k, 1:k) * x_EW

Sigma2_C = (np.sum(Sigma) - np.trace(Sigma)) / (n**2 - n)   # average covariance (trace = sum of the diagonal)
print("var_EW(1) =", var_EW[0], " var_EW(n) =", var_EW[-1], " Sigma2_C =", Sigma2_C)

# %% 4
plt.figure(1)
plt.plot(np.arange(1, n + 1), var_EW, linewidth=2)
plt.plot(np.arange(1, n + 1), np.ones(n) * Sigma2_C, linewidth=2)
plt.xlabel('n. of assets')
plt.ylabel('Variance')
plt.title("Fama's Experiment")
plt.show()

Results

Number of stocks Portfolio variance (weekly)
1 0.000898
10 0.000439
221 0.000307
Average covariance (floor) 0.000298

Variance of the equally weighted portfolio against the number of stocks

Takeaways

  • The first ten stocks remove half of the variance; the next two hundred remove little more.
  • The floor is the average covariance: market risk, which no amount of diversification removes.
  • The curve is not smooth because stocks are added in file order, not at random: each new stock can raise the variance as well as lower it.