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.
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
We can graphically represent the CAPM model with the following 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.
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.
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
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