Index Models

This notebook estimates (single and multi-) index models. It also evaluates how good these models are at capturing the covariances of different assets.

Load Packages and Extra Functions


In [2]:
using Dates, LinearAlgebra, Statistics, DelimitedFiles

include("jlFiles/printmat.jl")
include("jlFiles/printTable.jl")
include("jlFiles/OlsGMFn.jl")           #function for OLS


Out[2]:
OlsGMFn

The Theory: A Covariance Matrix from Betas

The single index model implies that the covariance of assets $i$ and $j$ is

$\sigma_{ij} = \beta_i \beta_j \text{Var}(R_{mt}) + \text{Cov}(\varepsilon_{it},\varepsilon_{jt}),$ but where $\text{Cov}(\varepsilon_{it},\varepsilon_{jt}) = 0 \ \text{ if } \ i \neq j$

The betas are typically estimated by a linear regression (OLS)

$R_{it} = \alpha_i + \beta_i R_{mt} + \varepsilon_{it}$

The next section gives a simple example.


In [3]:
β      = [0.9 1.1]            #βs of the two assets, row vector
VarRes = ([10 5]/100).^2      #var(ϵ) for the two assets, row vector
VarRm  = 0.15^2               #var(market return)

printblue("β:")
printmat(β)
printblue("VarRm*100^2:")
printmat(VarRm*100^2)
printblue("Var(residuals)*100^2:")
printmat(VarRes*100^2)


β:
     0.900     1.100

VarRm*100^2:
   225.000

Var(residuals)*100^2:
   100.000    25.000


In [4]:
"""
    CovFromIndexModel(b,VarRes,Ω)

Calculate covariance matrix from a multi-factor model.

Cov(Ri,Rj) = bᵢ'*Ω*bⱼ, where Ω is the Cov(indices) and bᵢ is the vector of regression
coefficients when regressing Ri on a constant and the indices (and bⱼ is for asset j).
"""
function CovFromIndexModel(b,VarRes,Ω)    #coefs for regression i is in b[:,i]
    n    = length(VarRes)
    CovR = fill(NaN,(n,n))
    for i = 1:n, j = 1:n         #loop over both i and j
        if i == j
            CovR[i,i] = b[:,i]'Ω*b[:,i] + VarRes[i]
        else
            CovR[i,j] = b[:,i]'Ω*b[:,j]
        end
    end
    return CovR
end

CovR = CovFromIndexModel(β,VarRes,VarRm)    #notice: use β' to get 1xn matrix
printblue("Covariance matrix*100^2 calculated from betas:")
printmat(CovR*100^2)


Covariance matrix*100^2 calculated from betas:
   282.250   222.750
   222.750   297.250

Estimating a Single-Index Model on Data

The next section applies the single index model on 5 of the (25) FF portfolios.

Loading Data


In [5]:
x    = readdlm("Data/FFmFactorsPs.csv",',',skipstart=1)
Rme  = x[:,2]                #market excess return
RSMB = x[:,3]                #small minus big firms
RHML = x[:,4]                #high minus low book-to-market ratio
Rf   = x[:,5]                #interest rate


x  = readdlm("Data/FF25Ps.csv",',') #no header line: x is matrix
R  = x[:,2:end]                     #returns for 25 FF portfolios
Re = R .- Rf                        #excess returns for the 25 FF portfolios
Re = Re[:,[1,7,13,19,25]]           #use just 5 assets to make the printing easier 

(T,n) = size(Re)                    #no. obs and  no. test assets


Out[5]:
(388, 5)

Regressions


In [6]:
x          = [ones(T) Rme]                   #regressors
(β,VarRes) = (fill(NaN,1,n),fill(NaN,n))
for i = 1:n
    #local b_i, ϵ_i                      #only needed in REPL/script
    (b_i,ϵ_i,_) = OlsGMFn(Re[:,i],x)     #OLS
    β[1,i]      = b_i[2]                 #2nd coef is for Rme
    VarRes[i]   = var(ϵ_i)
end

colNames = [string("asset ",i) for i=1:n]
printblue("β for $n assets, from OLS of Re on constant and Rme:")
printTable(β,colNames,["β on Rme"],)


β for 5 assets, from OLS of Re on constant and Rme:
           asset 1   asset 2   asset 3   asset 4   asset 5
β on Rme     1.341     1.169     0.994     0.943     0.849

Using OLS Estimates to Calculate the Covariance Matrix


In [7]:
VarRm = var(Rme)
CovR  = CovFromIndexModel(β,VarRes,VarRm)

printblue("Covariance matrix calculated from betas:")
printmat(CovR)

printblue("Covariance matrix calculated from data:")
printmat(cov(Re))

printblue("Difference between the two:")
printmat(CovR-cov(Re))


Covariance matrix calculated from betas:
    73.475    33.232    28.269    26.797    24.146
    33.232    37.371    24.644    23.361    21.049
    28.269    24.644    26.796    19.872    17.906
    26.797    23.361    19.872    25.200    16.973
    24.146    21.049    17.906    16.973    25.335

Covariance matrix calculated from data:
    73.475    43.024    29.472    25.013    20.188
    43.024    37.371    29.072    25.136    21.407
    29.472    29.072    26.796    23.632    20.981
    25.013    25.136    23.632    25.200    21.533
    20.188    21.407    20.981    21.533    25.335

Difference between the two:
     0.000    -9.791    -1.202     1.784     3.958
    -9.791    -0.000    -4.428    -1.775    -0.357
    -1.202    -4.428     0.000    -3.760    -3.075
     1.784    -1.775    -3.760     0.000    -4.560
     3.958    -0.357    -3.075    -4.560     0.000

A Multi-Index Model

A multi-index model is based on

$R_{it} =a_{i}+b_{i}^{\prime}I_{t}+\varepsilon_{it}$,

where $b_{i}$ is a $K\times 1$ vector of slope coefficients.

If $\Omega$ is the covariance matrix of the indices $I_t$, then the covariance of assets $i$ and $j$ is

$\sigma_{ij}=b_{i}^{\prime}\Omega b_{j} + \text{Cov}(\varepsilon_{it},\varepsilon_{jt}),$ but where $\text{Cov}(\varepsilon_{it},\varepsilon_{jt}) = 0 \ \text{ if } \ i \neq j$


In [8]:
x          = [ones(T) Rme RSMB RHML]               #regressors
K          = size(x,2) - 1 
(b,VarRes) = (fill(NaN,(K,n)),fill(NaN,n))         #b is Kxn
for i = 1:n
    #local b_i,ϵ_i                       #only needed in REPL/script
    (b_i,ϵ_i,_) = OlsGMFn(Re[:,i],x)     #OLS
    b[:,i]      = b_i[2:end]
    VarRes[i]   = var(ϵ_i)
end

printblue("OLS slope coefficients:")
printTable(b,colNames,["β on Rme", "β on RSMB", "β on RHML"])


OLS slope coefficients:
            asset 1   asset 2   asset 3   asset 4   asset 5
β on Rme      1.070     1.080     1.035     1.056     1.041
β on RSMB     1.264     0.768     0.437     0.153    -0.088
β on RHML    -0.278     0.160     0.487     0.603     0.770


In [9]:
Ω = cov(x[:,2:end])      #covariance matrix of factors

CovR = CovFromIndexModel(b,VarRes,Ω)

printblue("Covariance matrix calculated from betas:")
printmat(CovR)

printblue("Covariance matrix calculated from data:")
printmat(cov(Re))

printblue("Difference between the two:")
printmat(CovR-cov(Re))

printred("Is the multi-index model better than the single-index model?")


Covariance matrix calculated from betas:
    73.475    41.847    31.050    25.449    18.940
    41.847    37.371    27.384    24.141    20.145
    31.050    27.384    26.796    22.239    20.109
    25.449    24.141    22.239    25.200    20.717
    18.940    20.145    20.109    20.717    25.335

Covariance matrix calculated from data:
    73.475    43.024    29.472    25.013    20.188
    43.024    37.371    29.072    25.136    21.407
    29.472    29.072    26.796    23.632    20.981
    25.013    25.136    23.632    25.200    21.533
    20.188    21.407    20.981    21.533    25.335

Difference between the two:
    -0.000    -1.176     1.578     0.436    -1.248
    -1.176    -0.000    -1.688    -0.995    -1.261
     1.578    -1.688     0.000    -1.393    -0.873
     0.436    -0.995    -1.393     0.000    -0.816
    -1.248    -1.261    -0.873    -0.816     0.000

Is the multi-index model better than the single-index model?

In [ ]: