Author: Amaury LIN & Thierry ZHANG

R Markdown

Here the Markdown of : Calculating and visualizing a portfolio Beta in the Capital Asset Pricing Mode

Part 1 and 2

library(tidyverse)
## -- Attaching packages --------------------------------------- tidyverse 1.3.2 --
## v ggplot2 3.3.5      v purrr   0.3.4 
## v tibble  3.1.8      v dplyr   1.0.10
## v tidyr   1.2.1      v stringr 1.4.0 
## v readr   2.1.3      v forcats 0.5.2 
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
library(tidyquant)
## Le chargement a nécessité le package : lubridate
## Le chargement a nécessité le package : timechange
## 
## Attachement du package : 'lubridate'
## 
## Les objets suivants sont masqués depuis 'package:base':
## 
##     date, intersect, setdiff, union
## 
## Le chargement a nécessité le package : PerformanceAnalytics
## Le chargement a nécessité le package : xts
## Le chargement a nécessité le package : zoo
## 
## Attachement du package : 'zoo'
## 
## Les objets suivants sont masqués depuis 'package:base':
## 
##     as.Date, as.Date.numeric
## 
## 
## Attachement du package : 'xts'
## 
## Les objets suivants sont masqués depuis 'package:dplyr':
## 
##     first, last
## 
## 
## Attachement du package : 'PerformanceAnalytics'
## 
## L'objet suivant est masqué depuis 'package:graphics':
## 
##     legend
## 
## Le chargement a nécessité le package : quantmod
## Le chargement a nécessité le package : TTR
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
library(timetk)
library(broom)
library(ggplot2)
library(highcharter)
library(tibbletime)
## 
## Attachement du package : 'tibbletime'
## 
## L'objet suivant est masqué depuis 'package:stats':
## 
##     filter
library(scales)
## 
## Attachement du package : 'scales'
## 
## L'objet suivant est masqué depuis 'package:purrr':
## 
##     discard
## 
## L'objet suivant est masqué depuis 'package:readr':
## 
##     col_factor
#list that contains our stock symbol that we will use
symbols <- c("SPY","VGK", "SBGI", "MCHI","EFA")

#loading data from yahoo finance of our selected stocks from 2013 to 2017
prices <- getSymbols(symbols, src = 'yahoo',from = "2013-01-01",to = "2017-12-31",auto.assign = TRUE, warnings = FALSE) %>% 
  map(~Ad(get(.))) %>%
  reduce(merge) %>% 
  `colnames<-`(symbols)

#convert the daily data to a monthly format
prices_monthly <- to.monthly(prices, indexAt = "last", OHLC = FALSE)

#calculating the logarithmic monthly return of the stocks
asset_returns_xts <- na.omit(Return.calculate(prices_monthly, method = "log"))

#setting the weight of our stocks in the portfolio (25%, 25%, 20%, 20%, 10%)
w <- c(0.25, 0.25, 0.20, 0.20, 0.10)

#calculating the monthly return of the portfolio
portfolio_returns_xts <- Return.portfolio(asset_returns_xts, weights = w, rebalance_on = "months") %>%
  `colnames<-`("returns") 

#new format that store all of the monthly stocks returns in a single column
asset_returns_long <- prices %>% 
  to.monthly(indexAt = "last", OHLC = FALSE) %>% 
  tk_tbl(preserve_index = TRUE, rename_index = "date") %>%
  gather(asset, returns, -date) %>% 
  group_by(asset) %>%  
  mutate(returns = (log(returns) - log(lag(returns)))) %>% 
  na.omit()

#monthly return of the portfolio in a data frame format
portfolio_returns_tq_rebalanced_monthly <- asset_returns_long %>%
  tq_portfolio(assets_col  = asset, returns_col = returns, weights = w, col_rename  = "returns", rebalance_on = "months")

#loading data of the SPY from yahoo finance, it will be use to represent the market data
spy_monthly_xts <- getSymbols("SPY", src = 'yahoo', from = "2013-01-01", to = "2017-12-31", auto.assign = TRUE, warnings = FALSE) %>% 
  map(~Ad(get(.))) %>% 
  reduce(merge) %>%
  `colnames<-`("SPY") %>% 
  to.monthly(indexAt = "last", OHLC = FALSE)

#monthly return of the market in xts format
market_returns_xts <- Return.calculate(spy_monthly_xts, method = "log") %>% 
  na.omit()

#monthly return of the market in data frame format
market_returns_tidy <- market_returns_xts %>% 
  tk_tbl(preserve_index = TRUE, rename_index = "date") %>% 
  na.omit() %>%
  select(date, returns = SPY)

#calculating the beta of each asset of the portfolio by using SPY as the market
beta_assets <- asset_returns_long %>% 
  na.omit() %>% 
  nest(data = -asset) %>% 
  mutate(model = map(data, ~ lm(returns ~ market_returns_tidy$returns, data = .))) %>%
  mutate(model = map(model, tidy)) %>% 
  unnest(model) %>% 
  filter(term == "market_returns_tidy$returns") %>% 
  select(-term)

#portfolio beta
beta <- w[1] * beta_assets$estimate[1] + w[2] * beta_assets$estimate[2] + w[3] * beta_assets$estimate[3] + w[4] * beta_assets$estimate[4] + w[5] * beta_assets$estimate[5]


#calculating the alpha and the beta with Tidyverse
beta_dplyr_byhand <-
  portfolio_returns_tq_rebalanced_monthly %>% 
  do(model = lm(returns ~ market_returns_tidy$returns, data = .))
alpha = beta_dplyr_byhand[[1]][[1]][["coefficients"]][["(Intercept)"]]
beta = beta_dplyr_byhand[[1]][[1]][["coefficients"]][["market_returns_tidy$returns"]]

Including Plots

Part 3:

theme_update(plot.title = element_text(hjust = 0.5))

#this generate monthly return of individual assets scattered against monthly market returns
asset_returns_long %>% 
  group_by(asset) %>% 
  summarise(expected_return = mean(returns),
            stand_dev = sd(returns)) %>% 
  ggplot(aes(x = stand_dev, y = expected_return, color = asset)) +
  geom_point(size = 2) +
  ylab("expected return") +
  xlab("standard deviation") +
  ggtitle("Expected Monthly Returns v. Risk") +
  scale_y_continuous(label = function(x){ paste0(x, "%")}) 

#Visualization of the relationship between market with a scatter plot of market returns
asset_returns_long %>% 
  group_by(asset) %>% 
  summarise(expected_return = mean(returns),
            stand_dev = sd(returns)) %>% 
  ggplot(aes(x = stand_dev, y = expected_return, color = asset)) +
  geom_point(size = 2) +
  geom_point(aes(x = sd(portfolio_returns_tq_rebalanced_monthly$returns),  
                 y = mean(portfolio_returns_tq_rebalanced_monthly$returns)), 
             color = "cornflowerblue", 
             size = 3) +
  geom_text(
    aes(x = sd(portfolio_returns_tq_rebalanced_monthly$returns) * 1.09, 
        y = mean(portfolio_returns_tq_rebalanced_monthly$returns), 
        label = "portfolio")) +
  ylab("expected return") +
  xlab("standard deviation") +
  ggtitle("Expected Monthly Returns v. Risk") +
  scale_y_continuous(labels = function(x){ paste0(x, "%")}) 

#beta calculation from previous part, add simple regression line 
portfolio_returns_tq_rebalanced_monthly %>% 
  mutate(market_returns = market_returns_tidy$returns) %>% 
  ggplot(aes(x = market_returns, y = returns)) + 
  geom_point(color = "cornflowerblue") +
  geom_smooth(method = "lm", se = FALSE, color = "green", size = .5) +
  ylab("portfolio returns") +
  xlab("market returns") + 
  ggtitle("Scatterplot with regression line")
## `geom_smooth()` using formula 'y ~ x'

#add green line to the scatter's slope equale to beta calculation and a y-intercept labeled as alpha
portfolio_returns_tq_rebalanced_monthly %>% 
  mutate(market_returns = market_returns_tidy$returns) %>% 
  ggplot(aes(x = market_returns, y = returns)) + 
  geom_point(color = "cornflowerblue") +
  geom_abline(aes(
    intercept = alpha, 
    slope = beta), 
    color = "purple",
    size = .5) +
  ylab("portfolio returns") +
  xlab("market returns") +
  ggtitle("Scatterplot with hand calculated slope")

#add purple line and plot both line
portfolio_returns_tq_rebalanced_monthly %>% 
  mutate(market_returns = market_returns_tidy$returns) %>% 
  ggplot(aes(x = market_returns, y = returns)) + 
  geom_point(color = "cornflowerblue") +
  geom_abline(aes(intercept = alpha, slope = beta), color = "purple", size = .5) +
  geom_smooth(method = "lm", se = FALSE, color = "green", size = .5) +
  ylab("portfolio returns") +
  xlab("market returns") +
  ggtitle("Compare CAPM beta line to regression line")
## `geom_smooth()` using formula 'y ~ x'

Note that the echo = FALSE parameter was added to the code chunk to prevent printing of the R code that generated the plot.