(a)
# Obtain the monthly time series
library(tidyquant)
## Loading required package: lubridate
##
## Attaching package: 'lubridate'
## The following object is masked from 'package:base':
##
## date
## Loading required package: PerformanceAnalytics
## Loading required package: xts
## Loading required package: zoo
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
##
## Attaching package: 'PerformanceAnalytics'
## The following object is masked from 'package:graphics':
##
## legend
## Loading required package: quantmod
## Loading required package: TTR
## Version 0.4-0 included new data defaults. See ?getSymbols.
## Loading required package: tidyverse
## Warning: package 'tidyverse' was built under R version 3.4.4
## -- Attaching packages ----------------------------------------------------------- tidyverse 1.2.1 --
## v ggplot2 2.2.1 v purrr 0.2.4
## v tibble 1.4.2 v dplyr 0.7.4
## v tidyr 0.8.0 v stringr 1.3.0
## v readr 1.1.1 v forcats 0.3.0
## Warning: package 'ggplot2' was built under R version 3.4.4
## -- Conflicts -------------------------------------------------------------- tidyverse_conflicts() --
## x lubridate::as.difftime() masks base::as.difftime()
## x lubridate::date() masks base::date()
## x dplyr::filter() masks stats::filter()
## x dplyr::first() masks xts::first()
## x lubridate::intersect() masks base::intersect()
## x dplyr::lag() masks stats::lag()
## x dplyr::last() masks xts::last()
## x lubridate::setdiff() masks base::setdiff()
## x lubridate::union() masks base::union()
library(KFAS)
## Warning: package 'KFAS' was built under R version 3.4.4
data1 <-
tq_get("TB3MS", get = "economic.data",
from = "1980-01-01", to = "2017-12-31") %>%
rename(TB3MS = price) %>%
mutate(lTB3MS = log(TB3MS))
data2 <-
tq_get("^GSPC", get = "stock.prices", collapse = "monthly",
from = "1980-01-01", to = "2017-12-31") %>%
select(date, adjusted) %>%
mutate(monyear = as.yearmon(date)) %>%
group_by(monyear) %>%
summarise(SP500 = mean(adjusted)) %>%
ungroup()
data3 <-
tq_get("IBM", get = "stock.prices", collapse = "monthly",
from = "1980-01-01", to = "2017-12-31") %>%
select(date, adjusted) %>%
mutate(monyear = as.yearmon(date)) %>%
group_by(monyear) %>%
summarise(IBM = mean(adjusted)) %>%
ungroup()
(b)
# Construct the time series
rSP500 <- ts(100*diff(log(data2$SP500), differences = 1), start=c(1980,1), frequency = 12)
rIBM <- ts(100*diff(log(data3$IBM), differences = 1), start=c(1980,1), frequency = 12)
rTB3MS <- ts((data1$TB3MS)/12, start=c(1980,1), frequency = 12)
erSP500 <- rSP500 - rTB3MS # Excess Return for S&P500
erIBM <- rIBM - rTB3MS # Excess Return for IBM
par(mfrow=c(3,1))
plot(rSP500, main=expression("Monthly S&P500 Returns"))
plot(rIBM, main=expression("Monthly IBM Returns"))
plot(rTB3MS, main=expression("3 Month Tbill"))

par(mfrow=c(2,1))
plot(erSP500, main=expression("Excess Return for S&P500"))
plot(erIBM, main=expression("Excess Return for IBM"))

(c)
# Estimating CAPM - OLS
# Estimate a relating excess returns for IBM and excess returns for S&P500
# Since series do not align in time, we restrict them
# over the window from Feb 1980 to Dec 2017.
rSP5002 <- window(rSP500, start = 1980 + 2/12, end = 2017 + 12/12)
## Warning in window.default(x, ...): 'end' value not changed
rIBM2 <- window(rIBM, start = 1980 + 2/12, end = 2017 + 12/12)
## Warning in window.default(x, ...): 'end' value not changed
rTB3MS2 <- window(rTB3MS, start = 1980 + 2/12, end = 2017 + 12/12)
## Warning in window.default(x, ...): 'end' value not changed
erSP5002 <- rSP5002 - rTB3MS2 # Excess Return for SP500
erIBM2 <- rIBM2 - rTB3MS2 # Excess Return for IBM
OLS <- lm(erIBM2 ~ erSP5002)
alpha.ols <- OLS$coefficients[1]
beta.ols <- OLS$coefficients[2]
plot(erIBM2,erSP5002, main="OLS")
abline(lm(erSP5002~erIBM2))

summary(OLS)
##
## Call:
## lm(formula = erIBM2 ~ erSP5002)
##
## Residuals:
## Min 1Q Median 3Q Max
## -17.5289 -2.6650 0.1015 2.6284 19.0401
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.28485 0.23545 1.21 0.227
## erSP5002 0.94846 0.06563 14.45 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 4.987 on 451 degrees of freedom
## Multiple R-squared: 0.3165, Adjusted R-squared: 0.315
## F-statistic: 208.9 on 1 and 451 DF, p-value: < 2.2e-16
(d)
# Estimating CAPM - KFS
# Estimate a CAPM model with time varying coefficients at and bt using Kalman filter.
# Create a plot showing how the smoothed states at and bt changed over time.
# SS stands for State-Space
SS.erSP5002 <- as.ts(erSP5002)
SS.erIBM2 <- as.ts(erIBM2)
# get number of observatons
T <- length(SS.erSP5002)
# construct system matrices for state-space model - CAPM with time variables alpha and beta
Zt <- array(rbind(rep(1,T), SS.erSP5002), dim=c(1,2,T))
Ht <- matrix(NA)
Tt <- diag(2)
Rt <- diag(2)
Qt <- matrix(c(NA,0,0,NA), 2,2)
# use diffuse prior
a1 <- matrix(c(0, 1), 2, 1)
P1 <- matrix(0, 2, 2)
P1inf <- diag(2)
# define state-space CAPM model
y.SS <- SSModel(SS.erIBM2 ~ -1 + SSMcustom(Z=Zt, T=Tt, R=Rt, Q=Qt, a1=a1, P1=P1, P1inf=P1inf), H=Ht)
# estimate variances of innovations using maximum likelihood
y.SS.ML <- fitSSM(y.SS, inits = c(0.001,0.001,0.001), method="BFGS")
# Kalman filtering and smoothing, with parameters in Q and H set to maximum likelihood estimates
y.SS.KFS <- KFS(y.SS.ML$model)
# To extract the time-varying coefficients from this model we use
alpha.KFS <- ts( cbind(y.SS.KFS$a[,1], y.SS.KFS$alphahat[,1]), start=c(1980,2), frequency=12)
beta.KFS <- ts( cbind(y.SS.KFS$a[,2], y.SS.KFS$alphahat[,2]), start=c(1980,2), frequency=12)
par(mfrow=c(2,1), mar=c(2,2,2,1))
plot.ts(alpha.KFS, plot.type="single", xlab="",ylab="Alpha", col=c("blue","red"), lwd=2)
legend("topright", c("filtered","smoothed"), col=c("blue","red"), lwd=2, cex=0.7, bty="n")
plot.ts(beta.KFS, plot.type="single", xlab="",ylab="Beta", col=c("blue","red"), lwd=2)
legend("topright", c("filtered","smoothed"), col=c("blue","red"), lwd=2, cex=0.7, bty="n")

par(mfrow=c(2,1), mar=c(2,2,2,1))
plot.ts(alpha.KFS[,2], plot.type="single", xlab="",ylab="Alpha", col="red", lwd=2)
legend("topright", "smoothed", col="red", lwd=2, cex=0.7, bty="n")
plot.ts(beta.KFS[,2], plot.type="single", xlab="",ylab="Beta", col="red", lwd=2)
legend("topright", "smoothed", col="red", lwd=2, cex=0.7, bty="n")

(e)
# Compare at and bt
mean(OLS$coefficients[1])
## [1] 0.2848487
mean(OLS$coefficients[2])
## [1] 0.9484601
mean(y.SS.KFS$a[, 1])
## [1] 0.2869122
mean(y.SS.KFS$a[, 2])
## [1] 0.9919725
mean(y.SS.KFS$alphahat[, 1])
## [1] 0.2958768
mean(y.SS.KFS$alphahat[, 2])
## [1] 0.9492199
# The coefficients of KFS and OLS estimates are nearly identical; however, the alpha and beta from the OLS estimate is smaller than the KFS estimate.