Sample Implementation of Multifactor Risk Model

The multifactor risk model boils down to a simple calcuation, the portofolio variance which can be computed as
{% Variance = \vec{w}^T \Sigma \vec{w} %}
Here {% \Sigma %} is a covariance matrix. The essence of the model is to calculate this covariance matrix.

Multifactor Covariance Matrix

To calculate portfolio variance, we need to calculate the asset covariance matrix. In the multi index model we have
{% \Sigma = B \Sigma_I B^T + S %}
where {% \Sigma %} is the asset covariance, {% \Sigma_I %} is the covariance matrix of Index returns, {% B %} is a matrix of asset betas, and {% S %} is the diagonal matrix of idiosyncratic risks. (that is, {% S_{i,i} %} is the variance of the {% i^{th} %} asset's idiosyncratic factor )

{% \Sigma_I %} is a measured covariance matrix, using standard techniques. {% B %} is a matrix of betas, that is {% B = [\textbf{b}_1, \textbf{b}_2, ..., \textbf{b}_k] %} The vector {% \textbf{b}_k %} is each stock beta (exposure) to the kth index, or factor.

Calculating the Index Covariance

index_prices = filter(data, index_tickers) index_cov = calc_covariance(returns(index_prices))

Calculating the Factor Betas

betas = {} variances = {} for ticker in tickers: dataset = filter(data, [ticker, * index_tickers]) asset_returns = returns(dataset) regress = rg.ols(asset_returns, index_tickers, ticker, intercept=False) betas[ticker] = regress['coefficients'] ticker_returns = [ {ticker:x[ticker]} for x in dataset ]

Calculating the Idiosyncratic Risk

The idiosyncratic risk is the variance of the idiosyncratic risk factor. THis is the variance of the asset after you subract out the risk due to the index factors.

var_returns = [] for item in asset_returns: total = 0 for iticker in index_tickers: total += regress['coefficients'][iticker] * item[iticker] pass var_returns.append({ticker:item[ticker] - total}) pass variance = calc_covariance(var_returns) variances[ticker] = float(variance[ticker][ticker])

Full Script

''' calc_covariance is a function that calculates the covariance of the columns in a dataset. shoiuld return its result as a pandas dataframe ''' def variance(data, tickers, index_tickers, calc_covariance = vr.ewma_covariance): index_prices = filter(data, index_tickers) index_cov = calc_covariance(returns(index_prices)) betas = {} variances = {} for ticker in tickers: dataset = filter(data, [ticker, * index_tickers]) asset_returns = returns(dataset) regress = rg.ols(asset_returns, index_tickers, ticker, intercept=False) betas[ticker] = regress['coefficients'] ticker_returns = [ {ticker:x[ticker]} for x in dataset ] var_returns = [] for item in asset_returns: total = 0 for iticker in index_tickers: total += regress['coefficients'][iticker] * item[iticker] pass var_returns.append({ticker:item[ticker] - total}) pass variance = calc_covariance(var_returns) variances[ticker] = float(variance[ticker][ticker]) pass index_cov_matrix = np.zeros((len(index_tickers), len(index_tickers))) for index1, ticker1 in enumerate(index_tickers): for index2, ticker2 in enumerate(index_tickers): index_cov_matrix[index1][index2] = index_cov[ticker1][ticker2] pass pass beta_list = [] for ticker in tickers: row = [] beta_list.append(row) for index_ticker in index_tickers: row.append(betas[ticker][index_ticker]) pass pass beta_matrix = np.array(beta_list) covariance = beta_matrix @ index_cov_matrix @ beta_matrix.T diag_list = [ variances[ticker] for ticker in tickers ] covariance = covariance + np.diag(diag_list) def calc(weights): nonlocal covariance, tickers vect_list = [ weights[ticker] for ticker in tickers ] weights = np.array(vect_list).reshape(-1, 1) variance = weights.T @ covariance @ weights return float(variance[0][0]) return calc