We’re told that risk and return are positively related: the higher the risk, the higher the return. We assume it’s true ex-ante (security market line). But is it true ex-post?
library(tidyverse)
library(lubridate)
library(scales)
library(ggrepel)
library(tidyquant)
library(jsonlite)
theme_set(theme_minimal())
invisible(Sys.setlocale("LC_TIME", "en_US.UTF-8"))
# Load data
library(frenchdata)
industrydata <- frenchdata::download_french_data("49 Industry Portfolios")
industryrets <- industrydata$subsets |>
filter(name == "Average Value Weighted Returns -- Monthly") |>
unnest(data) |>
mutate(date = lubridate::ymd(paste0(date, "01"))) |>
mutate_if(is.numeric, function(x) ifelse(x == -99.99, NA_real_, x / 100)) |>
select(-name) |>
pivot_longer(-date) |>
arrange(name, date) |>
drop_na()
industryrets |> saveRDS("industryrets.RDS")
industryrets <- readRDS("industryrets.RDS") |>
rename(r = value)
industryrets |>
group_by(name, decade = paste0(floor(year(date) / 10) * 10, "s")) |>
summarise(n = n(),
mu = prod(1 + r)^(12/n()) - 1,
sd = sd(r, na.rm = TRUE)*sqrt(12)) |>
group_by(decade) |>
filter(n == max(n)) |>
ggplot(aes(x = sd, y = mu, label = name)) +
geom_smooth(method = "lm", se = FALSE, linewidth = 0.3, fullrange = T) +
geom_point(size = 0.6, alpha = 0.6) +
# red shaddow for y below 0
annotate("rect", xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = 0, fill = "red", alpha = 0.1) +
# geom_smooth(method = "lm", se = FALSE) +
scale_x_continuous(labels = scales::percent) +
scale_y_continuous(labels = scales::percent) +
coord_cartesian(xlim = c(0, 0.8)) +
labs(x = "Standard deviation", y = "Mean return", title = "Risk and return by industry") +
facet_wrap(~decade, scales = "fixed")
Risk-return is clearly upward sloping in the 1940s and 2020s. It’s somewhat upward sloping in the 1950s and 1960s. But in 6 out of 11 decades, it’s flat or downward sloping.
At least on indsutry level, risk and return are not positively related ex-post.