# Load packages

# Core
library(tidyverse)
library(tidyquant)

Goal

Collect individual returns into a portfolio by assigning a weight to each stock

five stocks: “SPY”, “EFA”, “IJS”, “EEM”, “AGG”

from 2012-12-31 to 2017-12-31

1 Import stock prices

# Choose stocks

symbols <- c("SPY", "EFA", "IJS", "EEM", "AGG")

# Using tq_get() ----
prices <- tq_get(x    = symbols,
                 get  = "stock.prices",
                 from = "2012-12-31",
                 to   = "2017-12-31")

2 Convert prices to returns

asset_returns_tbl <- prices %>%
  
  # Calculate monthly returns
  group_by(symbol) %>%
  tq_transmute(select     = adjusted,
               mutate_fun = periodReturn,
               period     = "monthly",
               type       = "log") %>%
  slice (-1) %>%
  ungroup() %>%
  
  # rename
  set_names(c("asset", "date", "returns"))

# period_returns = c("yearly", "quarterly", "monthly", "weekly")

3 Assign a weight to each asset

symbols <- asset_returns_tbl %>% distinct(asset) %>% pull()

w <- c(0.25,
       0.25,
       0.20,
       0.20,
       0.10)

w_tbl <- tibble(symbols, w)

4 Build a portfolio

portfolio_returns_rebalanced_monthly_tbl <- asset_returns_tbl %>%
  
  tq_portfolio(assets_col   = asset,
               returns_col  = returns,
               weights      = w_tbl,
               col_rename   = "returns",
               rebalance_on = "months")

portfolio_returns_rebalanced_monthly_tbl
## # A tibble: 60 × 2
##    date        returns
##    <date>        <dbl>
##  1 2013-01-31  0.0204 
##  2 2013-02-28 -0.00239
##  3 2013-03-28  0.0121 
##  4 2013-04-30  0.0174 
##  5 2013-05-31 -0.0128 
##  6 2013-06-28 -0.0247 
##  7 2013-07-31  0.0321 
##  8 2013-08-30 -0.0224 
##  9 2013-09-30  0.0511 
## 10 2013-10-31  0.0301 
## # ℹ 50 more rows
# write_rds(portfolio_returns_rebalanced_monthly_tbl,
#           "00_data/Ch03_portfolio_returns_rebalanced_monthly_tbl.rds")

5 Calculate Standard Deviation

portfolio_sd_tidyquant_builtin_percent <- portfolio_returns_rebalanced_monthly_tbl %>%
  
  tq_performance(Ra = returns,
                 Rb = NULL,
                 performance_fun = table.Stats) %>%
  
  select(Stdev) %>%
  mutate(tq_sd = round(Stdev, 4)*100)

portfolio_sd_tidyquant_builtin_percent
## # A tibble: 1 × 2
##    Stdev tq_sd
##    <dbl> <dbl>
## 1 0.0235  2.35

6 Plot

# Figure 4.1 Dispersion of Portfolio Returns ----

portfolio_returns_rebalanced_monthly_tbl %>%
  
  ggplot(aes(date, returns)) +
  geom_point(color = "cornflowerblue", size = 2) +
  
  labs(title = "Scatterplot of Returns by Date") +
  theme(plot.title = element_text(hjust = 0.5))

# Figure 4.2 Scatter of Returns Colored by Distance from Mean ----

sd_plot <- sd(portfolio_returns_rebalanced_monthly_tbl$returns)
mean_plot <- mean(portfolio_returns_rebalanced_monthly_tbl$returns)

portfolio_returns_rebalanced_monthly_tbl %>%
  
  mutate(hist_col = case_when(
    returns > mean_plot + sd_plot ~ "high",
    returns < mean_plot - sd_plot ~ "middle",
    TRUE                          ~ "low"
  )) %>%
  
  # Plot
  ggplot(aes(date, returns, col = hist_col)) +
  geom_point(size = 2) +
  
  labs(title = "Colored Scatter") +
  theme(plot.title = element_text(hjust = 0.5))

## Figure 4.3 Scatter of Returns with Line at Standard Deviation ----

sd_plot <- sd(portfolio_returns_rebalanced_monthly_tbl$returns)
mean_plot <- mean(portfolio_returns_rebalanced_monthly_tbl$returns)

portfolio_returns_rebalanced_monthly_tbl %>%
  
  mutate(hist_col = case_when(
     returns > mean_plot + sd_plot ~ "high",
     returns < mean_plot - sd_plot ~ "middle",
     TRUE                          ~ "low"
  )) %>%
  
  # Plot
  ggplot(aes(date, returns, col = hist_col)) +
  geom_point(size = 2) +
  
  labs(title = "Colored Scatter with Line") +
  theme(plot.title = element_text(hjust = 0.5)) +
  
  # Add lines
  geom_hline(yintercept = mean_plot - sd_plot, linetype = "dotted", color = "purple") +
  geom_hline(yintercept = mean_plot - sd_plot, linetype = "dotted", color = "purple")

# Figure 4.4 Asset and Portfolio Standard Deviation Comparison ----

portfolio_returns_rebalanced_monthly_tbl
## # A tibble: 60 × 2
##    date        returns
##    <date>        <dbl>
##  1 2013-01-31  0.0204 
##  2 2013-02-28 -0.00239
##  3 2013-03-28  0.0121 
##  4 2013-04-30  0.0174 
##  5 2013-05-31 -0.0128 
##  6 2013-06-28 -0.0247 
##  7 2013-07-31  0.0321 
##  8 2013-08-30 -0.0224 
##  9 2013-09-30  0.0511 
## 10 2013-10-31  0.0301 
## # ℹ 50 more rows
asset_returns_sd_tbl <- asset_returns_tbl %>%
  
  group_by(asset) %>%
  tq_performance(Ra = returns,
                 Rb = NULL,
                 performance_fun = table.Stats) %>%
  
  select(asset, Stdev) %>%
  ungroup() %>%
  
  # Add portfolio sd
  add_row(tibble(asset = "Portfolio",
                 Stdev = sd(portfolio_returns_rebalanced_monthly_tbl$returns)))

asset_returns_sd_tbl %>%
  
  # Plot
  ggplot(aes(asset, Stdev, dol = asset)) +
  geom_point() +
  ggrepel::geom_text_repel(aes(label = asset),
                           data = asset_returns_sd_tbl %>%
                             filter(asset == "Portfolio")) +
  
  labs(title = "")

# Figure 4.5 Expected Returns versus Risk ----

asset_returns_sd_tbl <- asset_returns_tbl %>%
  
  group_by(asset) %>%
  tq_performance(Ra = returns,
                 Rb = NULL,
                 performance_fun = table.Stats) %>%
  
  select(asset, Mean = ArithmeticMean, Stdev) %>%
  ungroup() %>%
  
  add_row(tibble(asset = "Portfolio",
                 Mean = mean(portfolio_returns_rebalanced_monthly_tbl$returns),
                 Stdev = sd(portfolio_returns_rebalanced_monthly_tbl$returns)))


asset_returns_sd_tbl %>%
  
  ggplot(aes(Stdev, Mean, col = asset)) +
  geom_point() +
  ggrepel::geom_text_repel(aes(label = asset))

# 3 Rolling Standard Deviation ----
# Why rolling sd?
# Suppose that we have 10 years of data and calculated standard deviation for every six months.
# Consider two different scenarios: 1) sd of each six-month period is always 3% and 
# 2) sd for each six-month period fluctuated between 0% and 6%.
# It's possible that both scenarios have the same 3% sd for the entire period, which are not the same.
# Rolling sd can show us what might have caused spikes in volatility.
# and consider dynamically rebalancing the portfolio to better manage the volatility

# Assign a value to winder
window <- 24

port_rolling_sd_tbl <- portfolio_returns_rebalanced_monthly_tbl %>%
  
  tq_mutate(select = returns,
            mutate_fun = rollapply,
            width = window,
            FUN = sd,
            col_rename = "rolling_sd") %>%
  select(date, rolling_sd) %>%
  na.omit()

# Figure 4.7 Rolling Volatility ggplot ----

port_rolling_sd_tbl %>%
  
  ggplot(aes(date, rolling_sd)) +
  geom_line(color = "cornflowerblue") +
  
  scale_y_continuous(labels = scales::percent) +
  scale_x_date(breaks = scales::breaks_pretty(n = 7)) +
  
  labs(title = "24-Month Rolling volatility",
       x = NULL,
       y = NULL) +
  theme(plot.title = element_text(hjust = 0.5))