Introductionn

The Capital Asset Pricingn Model (CAPM) is a formula used to determine whether investing in a partiular asset is profitable. Essentially, the question is, “Is the return on this asset worth the investment?” In this tutorial, we’ll apply the CAPM model to see whether or not a particular stock is worth the investment using a multiple regression model.

CAPM: The Formula

Economics is all about trade-offs. Under the CAPM formula, a stock, or any type of asset class, is essentially compared to a relatively risk-free asset, which is usually some sort of US government bonnd, since these assets have a very low probability of default. The CAPM formula is as follows

\[ \begin{aligned} \mathbf{E}(R_{i}) = R_{f} + \beta_{i}\big[\mathbf{E}(R_{m}) - R_{f})\big] &&& (1) \end{aligned} \] where

  • \(\mathbf{E}(R_{i})\) is the expected returnn of the asset.
  • \(R_{f}\) is the risk-free asset, typically a US government bond.
  • \(\beta_{i}\) is the sensitivity of the expected excess asset returns to the expected market returns.
  • \(\mathbf{E}(R_{m}) - R_{f}\) is the considered the risk premium.

We can graphically represent the CAPM model with the following graph

Graph 1: CAPM Graph

The Security Market Line (SML) depicts the different levels of market risk of various marketable assets plotted against the expected return line at any given point in time.

Our goal is to find the value of \(\beta_{i}\) using linear regression.

The Data

We’ll be using fake data to find the beta of each stock.

library(foreign)

capm <- read.dta('/Users/czar.yobero/Documents/stata/capm4.dta')
capm <- capm[2:length(capm)]  # We don't need the date for our purposes.

kable(head(capm, 11), format = 'html') %>%
  kable_styling(bootstrap_options = c('striped', 'hover'))
dis ge gm ibm msft xom mkt riskfree
0.080884 0.056218 -0.046296 -0.056153 0.154255 -0.030644 0.004529 0.004188
0.047368 0.003226 0.198490 0.059620 0.136154 0.081728 0.073230 0.004268
-0.046343 0.112379 -0.017226 -0.005386 0.056047 0.060784 0.051322 0.004358
0.168337 -0.011603 -0.005535 0.115523 0.006983 0.080407 0.010862 0.003940
-0.090818 -0.021277 0.074212 0.015922 -0.058946 -0.029461 -0.025755 0.003806
-0.072296 0.089955 -0.070435 -0.022872 0.277819 0.012411 0.031954 0.003919
-0.015158 -0.012517 0.082320 0.154056 0.014418 -0.015762 -0.023264 0.003954
-0.203267 -0.105521 -0.189283 -0.148340 -0.127345 -0.062669 -0.157667 0.003909
-0.075171 -0.001719 -0.055914 0.140954 0.147231 0.079274 0.063836 0.003357
0.063645 0.099764 0.151481 0.155642 -0.038047 0.014159 0.074357 0.002960
0.194896 0.032857 0.113749 0.113434 0.152302 0.052845 0.061986 0.003702
summary(capm)
##       dis                  ge                  gm           
##  Min.   :-0.267794   Min.   :-0.234902   Min.   :-0.389313  
##  1st Qu.:-0.043638   1st Qu.:-0.032974   1st Qu.:-0.076167  
##  Median : 0.005858   Median :-0.004716   Median :-0.013017  
##  Mean   : 0.001379   Mean   : 0.001361   Mean   :-0.009081  
##  3rd Qu.: 0.047858   3rd Qu.: 0.040096   3rd Qu.: 0.068138  
##  Max.   : 0.241453   Max.   : 0.192392   Max.   : 0.276619  
##       ibm                 msft                xom           
##  Min.   :-0.226453   Min.   :-0.343529   Min.   :-0.116462  
##  1st Qu.:-0.038707   1st Qu.:-0.056052   1st Qu.:-0.028031  
##  Median : 0.006482   Median : 0.003996   Median : 0.003309  
##  Mean   : 0.008332   Mean   : 0.008557   Mean   : 0.010488  
##  3rd Qu.: 0.051488   3rd Qu.: 0.056916   3rd Qu.: 0.041534  
##  Max.   : 0.353799   Max.   : 0.407781   Max.   : 0.232171  
##       mkt               riskfree       
##  Min.   :-0.184726   Min.   :0.000025  
##  1st Qu.:-0.022966   1st Qu.:0.001376  
##  Median : 0.010952   Median :0.002870  
##  Mean   : 0.002511   Mean   :0.002675  
##  3rd Qu.: 0.037875   3rd Qu.:0.003904  
##  Max.   : 0.083925   Max.   :0.005195
str(capm)
## 'data.frame':    132 obs. of  8 variables:
##  $ dis     : num  0.0809 0.0474 -0.0463 0.1683 -0.0908 ...
##  $ ge      : num  0.05622 0.00323 0.11238 -0.0116 -0.02128 ...
##  $ gm      : num  -0.0463 0.19849 -0.01723 -0.00553 0.07421 ...
##  $ ibm     : num  -0.05615 0.05962 -0.00539 0.11552 0.01592 ...
##  $ msft    : num  0.15426 0.13615 0.05605 0.00698 -0.05895 ...
##  $ xom     : num  -0.0306 0.0817 0.0608 0.0804 -0.0295 ...
##  $ mkt     : num  0.00453 0.07323 0.05132 0.01086 -0.02576 ...
##  $ riskfree: num  0.00419 0.00427 0.00436 0.00394 0.00381 ...

According to our data, we have six stocks in which we must decide whether the stock is invnestment worthy. Unfortunately, we can’t just fit our regression model just yet, due to the fact that we must first convert our data to formula \((1)\). We will have to calculate new variables based on the ones we have.

We need to calculate the risk premium of each stock \(\mathbf{E}(R_{m}) - R_{f}\).

capm$risk.premium <- capm$mkt - capm$riskfree
kable(head(capm, 5), format = 'html') %>%
  kable_styling(bootstrap_options = c('striped', 'hover'))
dis ge gm ibm msft xom mkt riskfree risk.premium
0.080884 0.056218 -0.046296 -0.056153 0.154255 -0.030644 0.004529 0.004188 0.000341
0.047368 0.003226 0.198490 0.059620 0.136154 0.081728 0.073230 0.004268 0.068962
-0.046343 0.112379 -0.017226 -0.005386 0.056047 0.060784 0.051322 0.004358 0.046964
0.168337 -0.011603 -0.005535 0.115523 0.006983 0.080407 0.010862 0.003940 0.006922
-0.090818 -0.021277 0.074212 0.015922 -0.058946 -0.029461 -0.025755 0.003806 -0.029561

Let’s take a look at a scatter plot of Microsoft’s stock (msft).

library(ggplot2)
theme_set(theme_bw())

ggplot(data = capm, aes(y = msft, x = risk.premium)) + geom_point(col='blue') + xlab('Risk Premium') + 
  ylab('Expected Return') + ggtitle('Microsoft Stock Returns') + geom_abline(method='lm')

It’s worth noting that the higher the risk premium, the greater the expected return should be. Otherwise, it wouldn’t be prudennt to invest in a high risk asset with expected low returns, as it would result in a loss.

Fitting Our Model

Now we can start to fit our regression model. First, we have to divide the data into training and test sets.

# We will need to create regression models for all six stocks.
dis.fit <- lm(dis ~ riskfree + risk.premium, data = capm)
ge.fit <- lm(ge ~ riskfree + risk.premium, data = capm)
gm.fit <- lm(gm ~ riskfree + risk.premium, data = capm)
ibm.fit <- lm(ibm ~ riskfree + risk.premium, data = capm)
msft.fit <- lm(msft ~ riskfree + risk.premium, data = capm)
xom.fit <- lm(xom ~ riskfree + risk.premium, data = capm)

# Create table
stock <- c('dis', 'ge', 'gm', 'ibm', 'msft', 'xom')
expected.return <- c(dis.fit$coefficients[3], 
                     ge.fit$coefficients[3],
                     gm.fit$coefficients[3],
                     ibm.fit$coefficients[3],
                     msft.fit$coefficients[3],
                     xom.fit$coefficients[3])
df <- data.frame(stock, expected.return)
kable(df, format = 'html') %>%
  kable_styling(bootstrap_options = c('striped', 'hover'))
stock expected.return
dis 0.8998424
ge 0.8882696
gm 1.2399124
ibm 1.1824380
msft 1.3111522
xom 0.4143299

How do we interpret the values of the risk premiums? Well, the higher the risk premium the more volatile or risky the asset is, and therefore investors should be compennsated with a return that justifies the risk of the asset.

Now that we have estimated our betas, we can calculate the expected return on each stock using formula \((1)\).

dis.predict <- predict.lm(dis.fit)
ge.predict <- predict.lm(ge.fit)
gm.predict <- predict.lm(gm.fit)
ibm.predict <- predict.lm(ibm.fit)
msft.predict <- predict.lm(msft.fit)
xom.predict <- predict.lm(xom.fit)

# add predictions to original data set
capm$dis.predict <- dis.predict
capm$ge.predict <- ge.predict
capm$gm.predict <- gm.predict
capm$ibm.predict <- ibm.predict
capm$msft.predict <- msft.predict
capm$xom.predict <- xom.predict

Fitted Regression Lines

dis.plot <- ggplot(capm, aes(y = dis.predict, x = risk.premium)) + 
  geom_smooth(col='tomato2', method='lm') + 
  geom_point(aes(y = dis, x = risk.premium)) + 
  ggtitle('Disney') + 
  xlab('Risk Premium') + 
  ylab('Expected Return')

ge.plot <- ggplot(capm, aes(y = ge.predict, x = risk.premium)) + geom_smooth(col='blue', method='lm') + 
  geom_point(aes(y = ge, x = risk.premium), col='red') + 
  ggtitle('General Electric') + 
  xlab('Risk Premium') + 
  ylab('Expected Return')

gm.plot <- ggplot(capm, aes(y = gm.predict, x = risk.premium)) + 
  geom_smooth(col='green', method='lm') +
  geom_point(aes(y = gm, x = risk.premium), col='tomato') +
  ggtitle('General Motors') + 
  xlab('Risk Premium') +
  ylab('Expected Return')

ibm.plot <- ggplot(capm, aes(y = ibm.predict, x = risk.premium)) +
  geom_smooth(method='lm', col='#36bfff') +
  geom_point(aes(y = ibm, x = risk.premium), col='#ff68f0') +
  ggtitle('IBM') +
  xlab('Risk Premium') +
  ylab('Expected Return')

msft.plot <- ggplot(capm, aes(y = msft.predict, x = risk.premium)) + 
  geom_smooth(method='lm', col='#448f1b') +
  geom_point(aes(y = msft, x = risk.premium), col='#e0c426') +
  ggtitle('Microsoft') + 
  xlab('Risk Premium') + 
  ylab('Expected Return')

xom.plot <- ggplot(capm, aes(y = xom.predict, x = risk.premium)) + 
  geom_smooth(method='lm', col='#e3933e') +
  geom_point(aes(y = xom, x = risk.premium), col = '#e6a6c6') +
  ggtitle('Exxon Mobil') +
  xlab('Risk Premium') +
  ylab('Expected Return')

dis.plot

ge.plot

gm.plot

ibm.plot

msft.plot

xom.plot