This analysis examines whether political party leadership affects daily stock market performance using S&P 500 index data from 1950 to 2018. The stock market is often cited in political discourse as an indicator of economic health, with both major parties claiming credit for strong performance during their administrations. To empirically test whether conservative (Republican) or liberal (Democratic) presidential leadership is associated with different rates of daily stock market change, this study compares the mean daily percentage change in the S&P 500 index across presidential administrations of each party.
Let \(\mu_{cons}\) represent the mean daily percentage change in the S&P 500 under conservative (Republican) leadership, and \(\mu_{lib}\) represent the mean daily percentage change under liberal (Democratic) leadership.
Null Hypothesis: \[H_0: \mu_{cons} - \mu_{lib} = 0\]
Alternative Hypothesis: \[H_a: \mu_{cons} - \mu_{lib} \neq 0\]
The alternative hypothesis suggests that conservative leadership is associated with statistically significantly different daily stock market gains compared to liberal leadership.
The dataset contains daily S&P 500 index values from 1950 to 2018. First, daily percentage changes are calculated using the adjusted closing price. Each trading day is then categorized by the political party of the sitting president. Presidential terms and party affiliations are matched to trading dates to enable comparison between Republican and Democratic administrations.
sp500 <- read_csv("https://www.openintro.org/data/csv/sp500_1950_2018.csv")
## Rows: 17346 Columns: 7
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## dbl (6): Open, High, Low, Close, Adj.Close, Volume
## date (1): Date
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
head(sp500)
## # A tibble: 6 × 7
## Date Open High Low Close Adj.Close Volume
## <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1950-01-03 16.7 16.7 16.7 16.7 16.7 1260000
## 2 1950-01-04 16.8 16.8 16.8 16.8 16.8 1890000
## 3 1950-01-05 16.9 16.9 16.9 16.9 16.9 2550000
## 4 1950-01-06 17.0 17.0 17.0 17.0 17.0 2010000
## 5 1950-01-09 17.1 17.1 17.1 17.1 17.1 2520000
## 6 1950-01-10 17.0 17.0 17.0 17.0 17.0 2160000
presidents <- tribble(
~president, ~party, ~start_date, ~end_date,
"Harry S. Truman", "Democrat", "1945-04-12", "1953-01-20",
"Dwight D. Eisenhower", "Republican", "1953-01-20", "1961-01-20",
"John F. Kennedy", "Democrat", "1961-01-20", "1963-11-22",
"Lyndon B. Johnson", "Democrat", "1963-11-22", "1969-01-20",
"Richard Nixon", "Republican", "1969-01-20", "1974-08-09",
"Gerald Ford", "Republican", "1974-08-09", "1977-01-20",
"Jimmy Carter", "Democrat", "1977-01-20", "1981-01-20",
"Ronald Reagan", "Republican", "1981-01-20", "1989-01-20",
"George H.W. Bush", "Republican", "1989-01-20", "1993-01-20",
"Bill Clinton", "Democrat", "1993-01-20", "2001-01-20",
"George W. Bush", "Republican", "2001-01-20", "2009-01-20",
"Barack Obama", "Democrat", "2009-01-20", "2017-01-20",
"Donald Trump", "Republican", "2017-01-20", "2021-01-20"
)
presidents <- presidents |>
mutate(
start_date = as.Date(start_date),
end_date = as.Date(end_date)
)
print(presidents)
## # A tibble: 13 × 4
## president party start_date end_date
## <chr> <chr> <date> <date>
## 1 Harry S. Truman Democrat 1945-04-12 1953-01-20
## 2 Dwight D. Eisenhower Republican 1953-01-20 1961-01-20
## 3 John F. Kennedy Democrat 1961-01-20 1963-11-22
## 4 Lyndon B. Johnson Democrat 1963-11-22 1969-01-20
## 5 Richard Nixon Republican 1969-01-20 1974-08-09
## 6 Gerald Ford Republican 1974-08-09 1977-01-20
## 7 Jimmy Carter Democrat 1977-01-20 1981-01-20
## 8 Ronald Reagan Republican 1981-01-20 1989-01-20
## 9 George H.W. Bush Republican 1989-01-20 1993-01-20
## 10 Bill Clinton Democrat 1993-01-20 2001-01-20
## 11 George W. Bush Republican 2001-01-20 2009-01-20
## 12 Barack Obama Democrat 2009-01-20 2017-01-20
## 13 Donald Trump Republican 2017-01-20 2021-01-20
sp500_clean <- sp500 |>
rename(date = Date, adj_close = Adj.Close) |>
mutate(date = as.Date(date)) |>
arrange(date) |>
mutate(daily_change = (adj_close - lag(adj_close)) / lag(adj_close) * 100) |>
drop_na(daily_change)
get_party <- function(date) {
for (i in 1:nrow(presidents)) {
if (date >= presidents$start_date[i] & date < presidents$end_date[i]) {
return(presidents$party[i])
}
}
return(NA)
}
sp500_clean <- sp500_clean |>
rowwise() |>
mutate(party = get_party(date)) |>
ungroup() |>
drop_na(party) |>
mutate(party = factor(party, levels = c("Republican", "Democrat")))
head(sp500_clean)
## # A tibble: 6 × 9
## date Open High Low Close adj_close Volume daily_change party
## <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <fct>
## 1 1950-01-04 16.8 16.8 16.8 16.8 16.8 1890000 1.14 Democrat
## 2 1950-01-05 16.9 16.9 16.9 16.9 16.9 2550000 0.475 Democrat
## 3 1950-01-06 17.0 17.0 17.0 17.0 17.0 2010000 0.295 Democrat
## 4 1950-01-09 17.1 17.1 17.1 17.1 17.1 2520000 0.589 Democrat
## 5 1950-01-10 17.0 17.0 17.0 17.0 17.0 2160000 -0.293 Democrat
## 6 1950-01-11 17.1 17.1 17.1 17.1 17.1 2630000 0.352 Democrat
party_means <- sp500_clean |>
group_by(party) |>
summarize(
mean_daily_change = mean(daily_change),
sd_daily_change = sd(daily_change),
n_days = n()
)
print(party_means)
## # A tibble: 2 × 4
## party mean_daily_change sd_daily_change n_days
## <fct> <dbl> <dbl> <int>
## 1 Republican 0.0232 1.01 9555
## 2 Democrat 0.0469 0.893 7790
yearly_summary <- sp500_clean |>
mutate(year = year(date)) |>
group_by(year, party) |>
summarize(mean_daily_change = mean(daily_change), .groups = "drop")
ggplot(yearly_summary, aes(x = year, y = mean_daily_change, color = party)) +
geom_point(alpha = 0.7) +
geom_hline(yintercept = 0, linetype = "dashed", color = "gray50") +
scale_color_manual(values = c("Republican" = "red", "Democrat" = "blue"),
labels = c("Republican (Conservative)", "Democrat (Liberal)")) +
labs(
title = "Average Daily S&P 500 Change by Year and Presidential Party",
x = "Year",
y = "Mean Daily Percentage Change (%)",
color = "Party"
) +
theme_minimal()
Before conducting the ANOVA, we verify the assumptions of normality and homogeneity of variance graphically.
Q-Q plots are used to visually assess whether the daily changes follow a normal distribution within each group.
republican_changes <- sp500_clean |>
filter(party == "Republican") |>
pull(daily_change)
democrat_changes <- sp500_clean |>
filter(party == "Democrat") |>
pull(daily_change)
par(mfrow = c(1, 2))
qqnorm(republican_changes, main = "Q-Q Plot: Republican")
qqline(republican_changes, col = "red")
qqnorm(democrat_changes, main = "Q-Q Plot: Democrat")
qqline(democrat_changes, col = "blue")
The Q-Q plots show some deviation from normality in the tails. However, ANOVA is robust to mild violations of normality, especially with large sample sizes.
ggplot(sp500_clean, aes(x = party, y = daily_change, fill = party)) +
geom_boxplot(outlier.alpha = 0.1) +
scale_fill_manual(values = c("Republican" = "red", "Democrat" = "blue")) +
labs(
title = "Distribution of Daily S&P 500 Changes by Presidential Party",
x = "Presidential Party",
y = "Daily Percentage Change (%)"
) +
theme_minimal() +
theme(legend.position = "none")
The boxplots show similar spread between groups, suggesting the homogeneity of variance assumption is reasonably met.
An ANOVA test is used to determine whether mean daily stock market changes differ significantly between Republican and Democratic administrations. This test compares group means and assesses whether observed differences exceed what would be expected by random variation.
anova_result <- aov(daily_change ~ party, data = sp500_clean)
summary(anova_result)
## Df Sum Sq Mean Sq F value Pr(>F)
## party 1 2 2.4240 2.623 0.105
## Residuals 17343 16029 0.9242
The ANOVA test yielded a p-value of 0.105, which is not statistically significant at the α = 0.05 level. Therefore, we fail to reject the null hypothesis. The mean daily percentage change under Republican leadership was 0.0232%, while under Democratic leadership it was 0.0469%.
Although the data shows a slightly higher mean daily return under Democratic administrations, this difference is not statistically significant (p = 0.105 > 0.05). We do not have sufficient evidence to conclude that presidential party affiliation has a meaningful effect on daily S&P 500 performance. The observed difference between parties could reasonably be attributed to random variation rather than a true underlying difference.
Important Limitations:
While this analysis examines the relationship between presidential party and stock market performance, several important caveats apply:
Correlation does not imply causation: Many factors influence stock market performance beyond presidential policy, including Federal Reserve actions, global economic conditions, congressional legislation, and business cycles.
Lag effects: Economic policies often take time to show effects, meaning a president’s policies may impact the market during subsequent administrations.
Congressional control: The party controlling Congress may have as much or more influence on economic policy as the president.
Market expectations: Markets may price in expected policy changes before a president takes office.
Sample composition: Different historical periods had different economic contexts (e.g., post-war boom, stagflation, tech bubble, financial crisis) that may confound results.
Further research could control for these confounding variables by including factors such as congressional party control, Federal Reserve policy, global economic indicators, and economic cycle phases.