Diagnostics, Validation & Export
Robust event study results require validation at every stage: data quality, model fit, and assumption checks. This page covers each diagnostic tool and what to do when checks fail, plus how to export results to CSV, Excel, and LaTeX for publication-ready reporting.
A systematic diagnostic workflow catches data errors and assumption violations before they undermine the credibility of published results. As documented by Campbell, Lo, and MacKinlay (1997), failing to check for residual non-normality or autocorrelation can inflate parametric test rejection rates by 10 to 20 percentage points above their nominal level. The four-step validation process below covers data quality, model fit, pre-trend analysis, and visual inspection.
Diagnostic Checklist
Event study diagnostics are a suite of statistical checks that validate model assumptions, data quality, and result reliability before publication. A well-conducted event study tests for normality of residuals (Shapiro-Wilk), absence of autocorrelation (Durbin-Watson statistic near 2.0), and no pre-event abnormal returns. According to Campbell, Lo, and MacKinlay (1997), failing to validate these assumptions can produce misleading significance levels and effect size estimates, particularly when residual non-normality inflates parametric test rejection rates by 10–20 percentage points.
| Check | Function | Pass Criterion | If Failed |
|---|---|---|---|
| Data quality | validate_task() | No warnings | Fix missing data, date gaps |
| Normality | model_diagnostics() — Shapiro-Wilk | p > 0.05 | Use non-parametric tests (Sign, Rank) |
| Autocorrelation | model_diagnostics() — Durbin-Watson | Stat near 2.0 | Use BMP test |
| Serial correlation | model_diagnostics() — Ljung-Box | p > 0.05 | Increase estimation window |
| Pre-trends | pretrend_test() | p > 0.05 (insignificant) | Re-check event date, shorten window |
| Model fit | model_diagnostics() — R² | Reasonable for asset class | Consider a different return model |
Data Validation
Run validate_task() before the event study to catch data problems early:
validate_task(task)The function checks:
- Event date exists in stock data
- Sufficient observations in the estimation window (minimum: 30)
- Time series gaps (flags gaps > 5 trading days)
- No window overlap between estimation and event windows
- Thin trading detection (> 10% zero returns)
Fix before proceeding
Validation warnings don’t stop execution, but they signal data issues that can bias results. Address warnings before interpreting abnormal returns.
Model Diagnostics
After fitting the model, assess residual quality. For a market model with a 120-day estimation window, a well-specified model typically yields an R-squared of 0.20–0.50, while the Durbin-Watson statistic should fall between 1.8 and 2.2:
diagnostics <- model_diagnostics(task)
print(diagnostics)Diagnostic Output
| Column | What It Tests | Interpretation |
|---|---|---|
| shapiro_p | Normality of residuals | p < 0.05 → residuals non-normal |
| dw_stat | First-order autocorrelation | < 1.5 or > 2.5 → autocorrelation present |
| ljung_box_p | Higher-order serial correlation | p < 0.05 → serial correlation present |
| acf1 | First-order autocorrelation coefficient | |acf1| > 0.1 → notable autocorrelation |
| sigma | Residual standard error | Larger → noisier model |
| r2 | R-squared | Higher → better model fit |
What to Do When Diagnostics Fail
Non-Normal Residuals (Shapiro-Wilk p < 0.05)
# Switch to non-parametric tests
ps <- ParameterSet$new(
multi_event_statistics = MultiEventStatisticsSet$new(
tests = list(SignTest$new(), RankTest$new(), GeneralizedSignTest$new())
)
)Autocorrelation (Durbin-Watson Far from 2)
# Use BMP test which is robust to cross-sectional correlation
ps <- ParameterSet$new(
multi_event_statistics = MultiEventStatisticsSet$new(
tests = list(BMPTest$new(), RankTest$new())
)
)Low R-squared
# Try a multi-factor model
ps <- ParameterSet$new(return_model = FamaFrench3FactorModel$new())
# Or increase estimation window
request$estimation_window_length <- 200Pre-Trend Testing
Pre-trend tests check whether abnormal returns existed before the event. Significant pre-event AR suggests information leakage, a confounding event, or a misspecified event date. Studies of insider trading events show that roughly 30–40% of M&A targets exhibit significant pre-event abnormal returns in the 5 days before announcement, highlighting the importance of this diagnostic.
pretrend <- pretrend_test(task)
print(pretrend)Pre-Trend Output
| Column | Meaning |
|---|---|
| n_pre_periods | Number of pre-event days tested |
| mean_pre_ar | Average pre-event abnormal return |
| t_stat | t-statistic for joint test |
| p_value | Significance (p < 0.05 → pre-trend detected) |
Pre-trend detected?
If pre-event AR are significant: (1) verify the event date against multiple sources, (2) shorten the event window, (3) check for confounding events, or (4) consider Panel DiD which explicitly tests parallel trends.
- Shapiro-Wilk Test
- A normality test for estimation-window residuals. A p-value below 0.05 indicates non-normal residuals, suggesting that non-parametric tests (Sign, Rank) should replace or supplement parametric alternatives.
- Durbin-Watson Statistic
- A test for first-order autocorrelation in residuals, ranging from 0 to 4. Values near 2.0 indicate no autocorrelation; values below 1.5 or above 2.5 suggest positive or negative autocorrelation, respectively.
- Pre-Trend Test
- A joint significance test of abnormal returns in the pre-event window, used to detect information leakage, confounding events, or misspecified event dates before interpreting post-event results.
Event Study Plots
Available Plot Types
| Type | Shows | Use For |
|---|---|---|
| "ar" | Abnormal returns per firm per day | Individual event-time impact |
| "car" | Cumulative AR per firm | Total firm-level impact |
| "aar" | Average AR across firms per day | Cross-sectional daily impact |
| "caar" | Cumulative average AR | Overall event impact (most common) |
Export Results
The package exports to CSV, Excel, and LaTeX. The format is auto-detected from the file extension.
CSV
export_results(task, file = "results/ar_results.csv", which = "ar")
export_results(task, file = "results/aar_results.csv", which = "aar")Excel
export_results(task, file = "results/event_study.xlsx",
which = c("ar", "car", "aar", "model"))Creates a multi-sheet workbook with auto-sized columns. One sheet per result type: Abnormal Returns, Cumulative AR, AAR & CAAR, Model Statistics. Requires openxlsx.
LaTeX
export_results(task, file = "results/tables/results.tex", which = "aar")Publication-ready tables with booktabs formatting and numeric columns rounded to 6 decimal places. Requires knitr.
Export Options
| Parameter | Options | Default |
|---|---|---|
| which | "ar", "car", "aar", "model" | All four |
| format | "csv", "xlsx", "latex" | Auto from extension |
| stat_name | Test statistic name for AAR tables | "CSectT" |
Diagnostic Plots
The four-panel diagnostic plot gives a quick visual assessment of model quality:
plot_diagnostics(task)Diagnostic Plot Panels
| Panel | What to Check |
|---|---|
| Residuals vs. Index | Random scatter around zero — no patterns or trends |
| Q-Q Plot | Points follow the diagonal — deviations indicate non-normality |
| Residual Histogram | Roughly bell-shaped — heavy tails suggest outliers |
| ACF of Residuals | Bars within blue bands — bars outside indicate autocorrelation |
Tidy Output
tidy.EventStudyTask() returns results as a tibble for piping into ggplot2 or other tidyverse tools:
tidy_results <- tidy.EventStudyTask(task, type = "aar")
print(tidy_results)Extract Specific Results
# Individual result components
ar <- task$get_ar(event_id = 1) # Abnormal returns for firm 1
car <- task$get_car(event_id = 1) # Cumulative AR for firm 1
aar <- task$get_aar() # Average abnormal returns (all groups)Complete Diagnostic Workflow
library(EventStudy)
# 1. Setup
task <- EventStudyTask$new(firm_data, index_data, request)
ps <- ParameterSet$new()
# 2. Validate input data
validate_task(task)
# 3. Run event study
task <- run_event_study(task, ps)
# 4. Diagnose
model_diagnostics(task)
pretrend_test(task)
plot_diagnostics(task)
# 5. Visualize
plot_event_study(task, type = "caar")
# 6. Export
export_results(task, file = "output/results.xlsx", which = c("ar", "car", "aar"))
export_results(task, file = "output/tables/aar.tex", which = "aar")Literature
- Campbell, J.Y., Lo, A.W. & MacKinlay, A.C. (1997). The Econometrics of Financial Markets. Chapter 4.
- Kolari, J.W. & Pynnönen, S. (2010). Event Studies for Financial Research.
Run this in R
The EventStudy R package lets you run these calculations programmatically with full control over parameters.
What Should I Read Next?
- Expected Return Models — choose the right model for your study
- Test Statistics — significance testing framework
- Assumptions — when assumptions are violated
- Getting Started — quick start guide