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"))
library(knitr)
library(elections)
# . $XLC, $XLY, $XLP, $XLE, $XLF, $XLV, $XLI, $XLB, $XLRE, $XLK, $XLU
sector_etfs <- tq_get(c("XLC", "XLY", "XLP", "XLE", "XLF", "XLV", "XLI", "XLB", "XLRE", "XLK", "XLU", "SPY"), from = 0) |>
group_by(symbol) |>
transmute(symbol, date, r = adjusted/lag(adjusted)-1) |>
ungroup() |>
drop_na()
sector_etfs |> saveRDS("data/sector_etfs.RDS")
sector_etfs <- readRDS("data/sector_etfs.RDS")
# data(eldat)
eldat <- readRDS("data/eldat.RDS")
election_dates <- eldat |>
as_tibble() |>
filter(electionyear > 1995) |>
bind_rows(tibble(electionyear = 2020, presel.Date = as.Date("2020-11-03"),
winner = "Joe Biden", winnerparty = "Dem."))
out <- tibble()
for (i in 1:nrow(election_dates)) {
temp <- sector_etfs |>
filter(date >= election_dates$presel.Date[i],
date <= election_dates$presel.Date[i]+126) |>
group_by(symbol) |>
summarise(r = prod(1+r)-1) |>
mutate(electionyear = election_dates$electionyear[i],
winner = election_dates$winner[i],
winnerparty = election_dates$winnerparty[i])
out <- bind_rows(out, temp)
}
out |>
ggplot(aes(y = r, fill = winnerparty, x = symbol)) +
geom_col() +
geom_text(aes(label = ifelse(r > 0, scales::percent(r, accuracy = 0.1), NA_character_)),
size = 4, nudge_y = 0.11) +
geom_text(aes(label = ifelse(r <= 0, scales::percent(r, accuracy = 0.1), NA_character_)),
size = 4, nudge_y = -0.11) +
geom_hline(yintercept = 0, linewidth = 0.2) +
scale_fill_manual(values = c("blue", "red")) +
scale_y_continuous(labels = scales::percent) +
facet_wrap(~paste(electionyear, winner), ncol = 1, scales = "fixed") +
labs(title = "Sector ETFs: US Presidential Elections",
subtitle = "Performance 6 months after the election",
x = "Sector ETF", y = "Return") +
theme(legend.position = "none")
# presidents |>
# saveRDS("data/presidents.RDS")
#
# spx_extended |>
# saveRDS("data/spx_extended.RDS")
presidents <- readRDS("data/presidents.RDS")
spx_extended <- readRDS("data/spx_extended.RDS")
df <- spx_extended %>%
full_join(presidents %>%
select(no_a, name, date = term_start, start = term_start, end = term_end, party = party_b_15_2),
by = "date") %>%
arrange(date) %>%
mutate_if(is.character, na.locf0) %>%
mutate_if(is.Date, na.locf0) %>%
filter(!is.na(SPX)) %>%
mutate(p = cumprod(1+SPX)*100) %>%
ungroup()
df_mid <- df %>%
group_by(name) %>%
filter(row_number() == round(n()/2))
df_m <- spx_extended %>%
full_join(presidents %>%
select(name, date = term_start, start = term_start, end = term_end, party = party_b_15_2),
by = "date") %>%
arrange(date) %>%
mutate_if(is.character, na.locf0) %>%
mutate_if(is.Date, na.locf0) %>%
filter(!is.na(SPX)) %>%
mutate(p = cumprod(1+SPX)*100) %>%
group_by(w = floor_date(date, "months")) %>%
filter(date == max(date)) %>%
ungroup()
df_m_mid <- df %>%
group_by(name) %>%
mutate(r = last(p)/first(p)-1) |>
group_by(name) %>%
filter(row_number() == round(n()/2))
percent_plus_minus <- function(x, accuracy = 0.1) {
if (x > 0) {
paste0("+", percent(x, accuracy = accuracy))
} else {
percent(x, accuracy = accuracy)
}
}
percent_plus_minus <- Vectorize(percent_plus_minus)
p <- df_m %>%
ggplot(aes(x = date, y = p)) +
geom_line(aes(color = party, group = 1)) +
geom_text_repel(data = df_m_mid, aes(label = paste0(name, "\n", percent_plus_minus(r, accuracy = 0.1))),
size = 2.5, nudge_y = 0.5, segment.alpha = 0.4) +
# geom_text_repel(data = df_m_mid, aes(label = percent_plus_minus(r, accuracy = 0.1)), size = 2.5, nudge_y = 0.1, segment.alpha = 0.4) +
scale_y_log10(labels = number) +
scale_color_manual(values = c("blue","red")) +
scale_x_date(date_breaks = "5 years", date_labels = "%Y", expand = c(0,0)) +
labs(x = NULL, y = "S&P 500 (TR, 1928=100)", color = NULL, fill = NULL) +
theme_minimal() +
theme(legend.position = "top")
p
Same but with election dates
# library(elections)
# data(eldat)
# eldat |> saveRDS("data/eldat.RDS")
eldat <- readRDS("data/eldat.RDS")
election_dates <- eldat |>
as_tibble() |>
# filter(electionyear > 1995) |>
bind_rows(tibble(electionyear = 2020, presel.Date = as.Date("2020-11-03"),
winner = "Joe Biden", winnerparty = "Dem.")) |>
group_by(winner) |>
slice_head(n = 1)
election_dates <- election_dates |>
mutate(winner = case_when(
winner == "Dwight Eisenhower" ~ "Dwight D. Eisenhower",
winner == "Franklin Roosevelt" ~ "Franklin D. Roosevelt",
winner == "Harry Truman" ~ "Harry S. Truman",
winner == "John Kennedy" ~ "John F. Kennedy",
winner == "Lyndon Johnson" ~ "Lyndon B. Johnson",
winner == "Warren Harding" ~ "Warren G. Harding",
TRUE ~ winner
)) |>
arrange(presel.Date) |>
mutate(nextelect = lead(presel.Date)-1)
df <- spx_extended %>%
full_join(presidents %>%
left_join(election_dates, by = c("name" = "winner")) %>%
select(no_a, name, date = presel.Date, start = presel.Date, end = nextelect, party = party_b_15_2),
by = "date") %>%
arrange(date) %>%
mutate_if(is.character, na.locf0) %>%
mutate_if(is.Date, na.locf0) %>%
filter(!is.na(SPX)) %>%
mutate(p = cumprod(1+SPX)*100) %>%
ungroup()
df_mid <- df %>%
group_by(name) %>%
filter(row_number() == round(n()/2))
df_m <- spx_extended %>%
full_join(presidents %>%
left_join(election_dates, by = c("name" = "winner")) %>%
select(no_a, name, date = presel.Date, start = presel.Date, end = nextelect, party = party_b_15_2),
by = "date") %>%
arrange(date) %>%
mutate_if(is.character, na.locf0) %>%
mutate_if(is.Date, na.locf0) %>%
filter(!is.na(SPX)) %>%
mutate(p = cumprod(1+SPX)*100) %>%
group_by(w = floor_date(date, "months")) %>%
filter(date == max(date)) %>%
ungroup()
df_m_mid <- df %>%
group_by(name) %>%
mutate(r = last(p)/first(p)-1) |>
group_by(name) %>%
filter(row_number() == round(n()/2))
p <- df_m %>%
left_join(election_dates, by = c("name" = "winner")) %>%
ggplot(aes(x = date, y = p)) +
geom_line(aes(color = party, group = 1)) +
geom_text_repel(data = df_m_mid, aes(label = paste0(name, "\n", percent_plus_minus(r, accuracy = 0.1))),
size = 2.5, nudge_y = 0.5, segment.alpha = 0.4) +
annotate("text", x = as.Date("1950-01-01"), y = 150000, label = "By election dates",
color = "darkred", size = 5) +
# geom_text_repel(data = df_m_mid, aes(label = percent_plus_minus(r, accuracy = 0.1)), size = 2.5, nudge_y = 0.1, segment.alpha = 0.4) +
scale_y_log10(labels = number) +
scale_color_manual(values = c("blue","red")) +
scale_x_date(date_breaks = "5 years", date_labels = "%Y", expand = c(0,0)) +
labs(x = NULL, y = "S&P 500 (TR, 1928=100)", color = NULL, fill = NULL) +
theme_minimal() +
theme(legend.position = "top")
p