library(tidyverse)
library(DBI)
library(scales)
library(lmtest)
library(sandwich)
9 Value and Bivariate Sorts: Original version
<- dbConnect(
tidy_finance ::duckdb(),
duckdb"data/tidy_finance.duckdb",
read_only = TRUE)
<- tbl(tidy_finance, "crsp_monthly") |>
crsp_monthly collect()
<- crsp_monthly |>
crsp_monthly select(
permno, gvkey, month, ret_excess,
mktcap, mktcap_lag, exchange|>
) drop_na()
<- tbl(tidy_finance, "compustat") |>
compustat collect()
<- compustat |>
be select(gvkey, datadate, be) |>
drop_na() |>
mutate(month = floor_date(ymd(datadate), "month"))
9.1 Book-to-Market Ratio
<- crsp_monthly |>
me mutate(sorting_date = month %m+% months(1)) |>
select(permno, sorting_date, me = mktcap)
<- be |>
bm inner_join(crsp_monthly |>
select(month, permno, gvkey, mktcap), by = c("gvkey", "month")) |>
mutate(
bm = be / mktcap,
sorting_date = month %m+% months(6),
comp_date = sorting_date
|>
) select(permno, gvkey, sorting_date, comp_date, bm)
<- crsp_monthly |>
data_for_sorts left_join(bm, by = c("permno",
"gvkey",
"month" = "sorting_date"
|>
)) left_join(me, by = c("permno", "month" = "sorting_date")) |>
select(
permno, gvkey, month, ret_excess,
mktcap_lag, me, bm, exchange, comp_date
)
<- data_for_sorts |>
data_for_sorts arrange(permno, gvkey, month) |>
group_by(permno, gvkey) |>
fill(bm, comp_date) |>
filter(comp_date > month %m-% months(12)) |>
select(-comp_date) |>
drop_na()
<- function(data,
assign_portfolio
sorting_variable,
n_portfolios,
exchanges) {<- data |>
breakpoints filter(exchange %in% exchanges) |>
pull({{ sorting_variable }}) |>
quantile(
probs = seq(0, 1, length.out = n_portfolios + 1),
na.rm = TRUE,
names = FALSE
)
<- data |>
assigned_portfolios mutate(portfolio = findInterval(
pick(everything()) |>
pull({{ sorting_variable }}),
breakpoints,all.inside = TRUE
|>
)) pull(portfolio)
return(assigned_portfolios)
}
9.2 Independent Sorts
<- data_for_sorts |>
value_portfolios group_by(month) |>
mutate(
portfolio_bm = assign_portfolio(
data = pick(everything()),
sorting_variable = "bm",
n_portfolios = 5,
exchanges = c("NYSE")
),portfolio_me = assign_portfolio(
data = pick(everything()),
sorting_variable = "me",
n_portfolios = 5,
exchanges = c("NYSE")
),portfolio_combined = str_c(portfolio_bm, portfolio_me)
|>
) group_by(month, portfolio_combined) |>
summarize(
ret = weighted.mean(ret_excess, mktcap_lag),
portfolio_bm = unique(portfolio_bm),
.groups = "drop"
)
<- value_portfolios |>
value_premium group_by(month, portfolio_bm) |>
summarize(ret = mean(ret), .groups = "drop_last") |>
summarize(value_premium = ret[portfolio_bm == max(portfolio_bm)] -
== min(portfolio_bm)])
ret[portfolio_bm
mean(value_premium$value_premium * 100)
[1] 0.3842144
9.3 Dependent Sorts
<- data_for_sorts |>
value_portfolios group_by(month) |>
mutate(portfolio_me = assign_portfolio(
data = pick(everything()),
sorting_variable = "me",
n_portfolios = 5,
exchanges = c("NYSE")
|>
)) group_by(month, portfolio_me) |>
mutate(
portfolio_bm = assign_portfolio(
data = pick(everything()),
sorting_variable = "bm",
n_portfolios = 5,
exchanges = c("NYSE")
),portfolio_combined = str_c(portfolio_bm, portfolio_me)
|>
) group_by(month, portfolio_combined) |>
summarize(
ret = weighted.mean(ret_excess, mktcap_lag),
portfolio_bm = unique(portfolio_bm),
.groups = "drop"
)
<- value_portfolios |>
value_premium group_by(month, portfolio_bm) |>
summarize(ret = mean(ret), .groups = "drop_last") |>
summarize(value_premium = ret[portfolio_bm == max(portfolio_bm)] -
== min(portfolio_bm)])
ret[portfolio_bm
mean(value_premium$value_premium * 100)
[1] 0.3288267