---
title: "Cross-Sectional Analysis of Event Study Results"
author: "Simon Mueller"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Cross-Sectional Analysis}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  eval = FALSE
)
```

# Introduction

After running an event study, a natural follow-up question is: **why do some
firms react more strongly than others?** Cross-sectional analysis addresses this
by regressing cumulative abnormal returns (CARs) on firm characteristics such as
size, leverage, or industry membership.

The EventStudy package provides three functions for cross-sectional analysis:

| Function | Purpose |
|----------|---------|
| `cross_sectional_regression()` | OLS regression of CARs on firm characteristics |
| `car_by_group()` | Compare CARs across groups (t-test or ANOVA) |
| `car_quantiles()` | Compute quantiles of the CAR distribution |

Additionally, `plot_car_distribution()` provides visual exploration of the CAR
distribution.

```{r load-packages}
library(EventStudy)
library(dplyr)
library(ggplot2)
```

# Running the Event Study First

Cross-sectional analysis requires a completed event study. Let's set up a
multi-firm study with two groups:

```{r run-study}
set.seed(42)

n <- 300
dates <- format(seq(as.Date("2014-06-01"), by = "day", length.out = n),
                "%d.%m.%Y")

# Four firms, two groups
firms <- c("FIRM_A", "FIRM_B", "FIRM_C", "FIRM_D")
firm_tbl <- purrr::map_dfr(firms, function(sym) {
  tibble(
    symbol   = sym,
    date     = dates,
    adjusted = 100 * cumprod(1 + rnorm(n, 0.0003, 0.015))
  )
})

index_tbl <- tibble(
  symbol   = "INDEX_1",
  date     = dates,
  adjusted = 1000 * cumprod(1 + rnorm(n, 0.0002, 0.012))
)

request_tbl <- tibble(
  event_id                = 1:4,
  firm_symbol             = firms,
  index_symbol            = rep("INDEX_1", 4),
  event_date              = rep(dates[200], 4),
  group                   = c("Large", "Large", "Small", "Small"),
  event_window_start      = rep(-10L, 4),
  event_window_end        = rep(10L, 4),
  shift_estimation_window = rep(-11L, 4),
  estimation_window_length = rep(150L, 4)
)

task <- EventStudyTask$new(firm_tbl, index_tbl, request_tbl)
task <- run_event_study(task)
```

# Cross-Sectional Regression

## Basic Usage

`cross_sectional_regression()` regresses CARs on firm-level explanatory
variables. The `data` argument must include an `event_id` column for merging:

```{r csreg-basic}
firm_chars <- tibble(
  event_id       = 1:4,
  log_market_cap = c(10.2, 11.5, 8.3, 9.1),
  leverage       = c(0.3, 0.5, 0.2, 0.4),
  r_and_d        = c(0.05, 0.02, 0.08, 0.06)
)

result <- cross_sectional_regression(
  task,
  formula = ~ log_market_cap + leverage,
  data    = firm_chars
)

print(result)
#> Cross-Sectional Regression of CARs
#> ===================================
#> N: 4
#> R-squared: 0.85
#> Adj. R-squared: 0.55
#>
#> Coefficients:
#>                 estimate std.error statistic p.value
#> (Intercept)      0.1234    0.0567     2.178  0.1615
#> log_market_cap  -0.0123    0.0054    -2.278  0.1500
#> leverage        -0.0456    0.0321    -1.421  0.2912
```

The formula follows R conventions: the left-hand side is ignored (CAR is always
the dependent variable), and the right-hand side specifies the explanatory
variables.

## Robust Standard Errors

By default, heteroskedasticity-consistent (HC1) standard errors are computed
using the `sandwich` package. To use OLS standard errors instead:

```{r csreg-robust}
# HC1 robust standard errors (default)
result_robust <- cross_sectional_regression(
  task, formula = ~ log_market_cap + leverage,
  data = firm_chars, robust = TRUE
)

# Plain OLS standard errors
result_ols <- cross_sectional_regression(
  task, formula = ~ log_market_cap + leverage,
  data = firm_chars, robust = FALSE
)
```

Install `sandwich` for robust standard errors: `install.packages("sandwich")`.

## Custom CAR Window

By default, the full event window is used to compute CARs. To focus on a
specific sub-window (e.g., the three-day window around the event):

```{r csreg-window}
result_3day <- cross_sectional_regression(
  task,
  formula    = ~ log_market_cap + leverage,
  data       = firm_chars,
  car_window = c(-1, 1)  # relative indices
)
```

## Accessing the Underlying Data

The result object includes the merged CAR + characteristics data, which is
useful for custom analyses:

```{r csreg-data}
# Merged data with CARs and firm characteristics
result$car_data
#> # A tibble: 4 x 6
#>   event_id firm_symbol group   car log_market_cap leverage
#>      <int> <chr>       <chr> <dbl>          <dbl>    <dbl>
#> ...

# The fitted lm object
summary(result$model)
```

# Group Comparisons

## car_by_group()

When events naturally fall into groups (e.g., large vs. small firms, industries,
treated vs. control), `car_by_group()` tests whether CARs differ across groups:

```{r group-comparison}
group_result <- car_by_group(task)

# Summary statistics by group
group_result$summary
#> # A tibble: 2 x 7
#>   group     n mean_car  sd_car median_car min_car max_car
#>   <chr> <int>    <dbl>   <dbl>      <dbl>   <dbl>   <dbl>
#>   Large     2   0.012   0.008      0.012   0.006   0.018
#>   Small     2  -0.005   0.003     -0.005  -0.007  -0.003

# Test result
group_result$test_name
#> [1] "Welch Two-Sample t-test"

group_result$test
```

The function automatically selects the appropriate test:
- **2 groups**: Welch two-sample t-test
- **3+ groups**: One-way ANOVA (Welch)

## Custom CAR Window for Groups

```{r group-window}
group_3day <- car_by_group(task, car_window = c(-1, 1))
group_3day$summary
```

# CAR Quantiles

`car_quantiles()` provides a quick summary of the CAR distribution:

```{r quantiles}
car_quantiles(task)
#>    5%   25%   50%   75%   95%
#> -0.02  0.00  0.01  0.02  0.03

# Custom quantiles
car_quantiles(task, probs = c(0.01, 0.1, 0.5, 0.9, 0.99))

# Quantiles for a specific CAR window
car_quantiles(task, car_window = c(0, 5))
```

# Visualizing the CAR Distribution

## Histogram

```{r plot-histogram, fig.width=7, fig.height=4}
plot_car_distribution(task)
```

## Histogram by Group

```{r plot-histogram-group, fig.width=7, fig.height=4}
plot_car_distribution(task, by_group = TRUE,
                      title = "CAR Distribution by Firm Size")
```

## Custom CAR Window

```{r plot-histogram-window, fig.width=7, fig.height=4}
plot_car_distribution(task, car_window = c(-1, 1),
                      title = "3-Day CAR Distribution")
```

# A Complete Cross-Sectional Workflow

Putting it all together---run the event study, then systematically explore and
explain cross-sectional variation:

```{r complete-workflow}
# 1. Run the event study
task <- EventStudyTask$new(firm_tbl, index_tbl, request_tbl)
task <- run_event_study(task)

# 2. Summary statistics
car_quantiles(task)

# 3. Group comparison
group_result <- car_by_group(task)
print(group_result$summary)

# 4. Visual exploration
plot_car_distribution(task, by_group = TRUE)

# 5. Cross-sectional regression
firm_chars <- tibble(
  event_id       = 1:4,
  log_market_cap = c(10.2, 11.5, 8.3, 9.1),
  leverage       = c(0.3, 0.5, 0.2, 0.4)
)

result <- cross_sectional_regression(
  task,
  formula = ~ log_market_cap + leverage,
  data    = firm_chars
)
print(result)

# 6. Robustness: different CAR windows
windows <- list(c(-1, 1), c(-5, 5), c(0, 10))
purrr::walk(windows, function(w) {
  r <- cross_sectional_regression(
    task, formula = ~ log_market_cap + leverage,
    data = firm_chars, car_window = w
  )
  cat("\nCAR window [", w[1], ",", w[2], "]:\n")
  print(r$coefficients)
})
```

# Tips and Best Practices

1. **Sample size matters.** Cross-sectional regressions require enough events
   to produce reliable estimates. With only a handful of firms, results will
   be fragile.

2. **Use robust standard errors.** Financial returns are heteroskedastic.
   Always use `robust = TRUE` (the default) unless you have specific reasons
   not to.

3. **Try multiple CAR windows.** Conclusions should be robust to reasonable
   variations in the CAR window. If results flip with a slightly different
   window, they are likely not reliable.

4. **Report group comparisons alongside regressions.** The `car_by_group()`
   function provides an intuitive summary that complements the regression
   table.

5. **Check the distribution.** Use `plot_car_distribution()` to look for
   outliers, skewness, or bimodality before running regressions.

# References

- MacKinlay, A. C. (1997). Event Studies in Economics and Finance. *Journal of Economic Literature*, 35(1), 13--39.
- Kothari, S. P. & Warner, J. B. (2007). Econometrics of Event Studies. In B. E. Eckbo (Ed.), *Handbook of Corporate Finance: Empirical Corporate Finance* (Vol. 1, pp. 3--36). Elsevier.
