Kurtosis

To readers of the book, there was an error in the book code where I missed a group_by(asset). Thanks very much to a kind reader for pointing this out! I have corrected the code below at line 223.

Kurtosis in the xts World

kurt_xts <-  
 kurtosis(portfolio_returns_xts_rebalanced_monthly$returns)

Kurtosis in the Tidyverse

kurt_tidy <-
  portfolio_returns_tq_rebalanced_monthly %>% 
  summarise(
  kurt_builtin = kurtosis(returns),
  kurt_byhand = 
  ((sum((returns - mean(returns))^4)/length(returns))/
  ((sum((returns - mean(returns))^2)/length(returns))^2)) - 3) %>% 
  select(kurt_builtin, kurt_byhand)
kurt_tidy %>% 
  mutate(xts = kurt_xts)
## # A tibble: 1 x 3
##   kurt_builtin kurt_byhand   xts
##          <dbl>       <dbl> <dbl>
## 1        0.457       0.457 0.457

Visualizing Kurtosis

portfolio_density_plot <- 
  portfolio_returns_tq_rebalanced_monthly %>% 
  ggplot(aes(x = returns)) +
  stat_density(geom = "line", 
               alpha = 1, 
               colour = "cornflowerblue")

median <- 
  median(portfolio_returns_tq_rebalanced_monthly$returns)
mean <- 
  mean(portfolio_returns_tq_rebalanced_monthly$returns)

shaded_area_data <- 
  ggplot_build(portfolio_density_plot)$data[[1]] %>% 
  filter(x < mean)

median_line_data <- 
  ggplot_build(portfolio_density_plot)$data[[1]] %>% 
  filter(x <= median)

sd_pos <- 
  mean + 
  (2* sd(portfolio_returns_tq_rebalanced_monthly$returns))
sd_neg <-
  mean - 
  (2* sd(portfolio_returns_tq_rebalanced_monthly$returns))

sd_pos_shaded_area <- 
  ggplot_build(portfolio_density_plot)$data[[1]] %>% 
  filter(x > sd_pos )

sd_neg_shaded_area <- 
  ggplot_build(portfolio_density_plot)$data[[1]] %>% 
  filter(x < sd_neg)

  portfolio_density_plot + 
  geom_area(data = sd_pos_shaded_area, 
            aes(x = x, y = y), 
            fill="pink", 
            alpha = 0.5) +
  geom_area(data = sd_neg_shaded_area,
            aes(x = x, y = y), 
            fill="pink", 
            alpha = 0.5) +
  scale_x_continuous(breaks = pretty_breaks(n = 10)) + 
  geom_area(data = sd_pos_shaded_area, 
            aes(x = x, y = y), 
            fill="pink", 
            alpha = 0.5) +
  geom_area(data = sd_neg_shaded_area, 
            aes(x = x, y = y), 
            fill="pink", 
            alpha = 0.5) +
  geom_segment(data = shaded_area_data, 
               aes(x = mean, 
                   y = 0, 
                   xend = mean, 
                   yend = density), 
               color = "red", 
               linetype = "dotted") +
  
  annotate(geom = "text", 
           x = mean, 
           y = 5, 
           label = "mean", 
           color = "red", 
           fontface = "plain", 
           angle = 90, 
           alpha = .8, 
           vjust =  -1.75) +
  
  geom_segment(data = median_line_data, 
               aes(x = median, 
                   y = 0, 
                   xend = median, 
                   yend = density), 
               color = "black", 
               linetype = "dotted") +
  
  annotate(geom = "text", 
           x = median,
           y = 5, 
           label = "median", 
           fontface = "plain", 
           angle = 90, 
           alpha = .8, 
           vjust =  1.75) +
  scale_x_continuous(breaks = pretty_breaks(n = 10))
Skewness ggplot

Figure 1: Skewness ggplot

asset_returns_long %>%
  # The following line group_by(asset) is not in the book! 
  # It was added after a tip from a very kind reader. I will post a full explanation of why it is needed and why it was missing to begin with. Mea culpa!
  group_by(asset) %>% 
  summarize(kurt_assets = kurtosis(returns)) %>% 
  add_row(asset = "Portfolio", 
          kurt_assets = kurt_tidy$kurt_byhand)%>% 
  ggplot(aes(x = asset, 
             y = kurt_assets, 
             colour = asset)) +
  geom_point() +
  geom_text(
        aes(x = "Portfolio", 
            y = 
              kurt_tidy$kurt_byhand + .06), 
              label = "Portfolio",
          color = "cornflowerblue") +
  # alternate geom_text()
  # Here's a way to label all the points
  # geom_text(aes(label = asset),
  #          nudge_y = .04)
  labs(y = "kurtosis")
Asset and Portfolio Kurtosis Comparison

Figure 2: Asset and Portfolio Kurtosis Comparison

Rolling Kurtosis in the xts World

window <- 24

rolling_kurt_xts <- 
  rollapply(portfolio_returns_xts_rebalanced_monthly,
            FUN = kurtosis,
            width = window) %>% 
  na.omit()

Rolling Kurtosis in the tidyverse with tibbletime

kurt_roll_24 <- 
  rollify(kurtosis, 
          window = window)
  
roll_kurt_tibbletime <- 
  portfolio_returns_tq_rebalanced_monthly %>%
  as_tbl_time(index = date) %>% 
  mutate(kurt = kurt_roll_24(returns)) %>% 
  select(-returns) %>% 
  na.omit()

Rolling Kurtosis in the tidyquant World

rolling_kurt_tq <- 
  portfolio_returns_tq_rebalanced_monthly %>% 
  tq_mutate(select = returns, 
            mutate_fun = rollapply,
            width      = window,
            FUN        = kurtosis,
            col_rename = "kurt") %>%
  select(-returns) %>%
  na.omit()
rolling_kurt_tq %>% 
  mutate(xts = coredata(rolling_kurt_xts),
         tbltime = roll_kurt_tibbletime$kurt) %>% 
  mutate_if(is.numeric, funs(round(.,3))) %>% 
  tail()
## # A tibble: 6 x 4
##   date        kurt   xts tbltime
##   <date>     <dbl> <dbl>   <dbl>
## 1 2017-07-31 0.604 0.604   0.604
## 2 2017-08-31 0.835 0.835   0.835
## 3 2017-09-30 1.22  1.22    1.22 
## 4 2017-10-31 2.13  2.13    2.13 
## 5 2017-11-30 2.22  2.22    2.22 
## 6 2017-12-31 3.38  3.38    3.38

Visualizing Rolling Kurtosis

highchart(type = "stock") %>%
  hc_title(text = "Rolling 24-Month kurtosis") %>%
  hc_add_series(rolling_kurt_xts, 
                name = "Rolling 24-Month kurtosis", 
                color = "cornflowerblue") %>%
  hc_yAxis(title = list(text = "kurtosis"),
           opposite = FALSE) %>%
  hc_xAxis(title = list(text = "")) %>%
  hc_navigator(enabled = FALSE) %>%    
  hc_scrollbar(enabled = FALSE) %>% 
  hc_add_theme(hc_theme_flat()) %>%
  hc_exporting(enabled = TRUE)

Figure 3: Rolling Kurtosis Highcharter

rolling_kurt_tq %>% 
  ggplot(aes(x = date, y = kurt)) + 
  geom_line(color = "cornflowerblue") +
  scale_y_continuous(breaks = pretty_breaks(n = 8)) + 
  scale_x_date(breaks = pretty_breaks(n = 8)) +
  ggtitle("Rolling 24-Month Kurtosis") +
  theme_update(plot.title = element_text(hjust = 0.5))
Rolling Kurtosis ggplot

Figure 4: Rolling Kurtosis ggplot

Share Comments