tests/test.sh exit code (0 → resolved); the classification below is post-hoc and cannot change it.cd /app && ls -la && echo "---DATA---" && ls -la data/ && echo "---R VERSION---" && Rscript --version 2>&1 | head -5
total 29 drwxrws--- 4 h2tagent h2tagent 4096 Jun 20 17:04 . drwxr-xr-x 26 root root 4096 Jun 20 17:55 .. -rw-rw---- 1 h2tagent h2tagent 12723 Jun 20 17:03 analysis.R drwxrws--- 2 h2tagent h2tagent 4096 Jun 20 17:04 data drwxrws--- 2 h2tagent h2tagent 4096 Jun 20 17:04 outputs ---DATA--- total 366 drwxrws--- 2 h2tagent h2tagent 4096 Jun 20 17:04 . drwxrws--- 4 h2tagent h2tagent 4096 Jun 20 17:04 .. -rw-rw---- 1 h2tagent h2tagent 903 Jun 20 17:03 firms.csv -rw-rw---- 1 h2tagent h2tagent 1716 Jun 20 17:03 recalls.csv -rw-rw---- 1 h2tagent h2tagent 363097 Jun 20 17:03 stock_returns.csv ---R VERSION--- Rscript (R) version 4.2.2 Patched (2022-11-10 r83330)
cd /app && echo "=== stock_returns.csv ===" && head -5 data/stock_returns.csv && echo "..." && wc -l data/stock_returns.csv && echo "" && echo "=== recalls.csv ===" && head -5 data/recalls.csv && wc -l data/recalls.csv && echo "" && echo "=== firms.csv ===" && head -5 data/firms.csv && wc -l data/firms.csv
=== stock_returns.csv === firm_id,date,return,market_return FIRM_004,2006-11-22,0.005192,-0.004466 FIRM_008,2006-12-11,0.033288,0.00112 FIRM_017,2007-05-16,-0.002451,0.026981 FIRM_018,2007-02-14,0.022314,0.033039 ... 9365 data/stock_returns.csv === recalls.csv === event_id,firm_id,date,hazard_type,units_recalled,media_articles,severity_score 1,FIRM_007,2007-03-21,burn,9186546,5,7.17 2,FIRM_002,2007-03-28,laceration,75169,3,1.21 3,FIRM_017,2007-04-16,choking,637374,4,4.6 4,FIRM_013,2007-04-20,lead_paint,681155,5,8.88 36 data/recalls.csv === firms.csv === firm_id,market_cap_mm,sic_code,beta,alpha,idio_vol,n_recalls FIRM_001,2606.23,3944,1.043,-0.000135,0.0152,4 FIRM_002,519.06,3944,0.6799,-0.000219,0.0187,2 FIRM_003,4449.48,3944,0.6878,-3.8e-05,0.0252,0 FIRM_004,5589.68,3942,1.4253,0.000847,0.0183,0 19 data/firms.csv
cd /app && cat analysis.R
suppressPackageStartupMessages({
library(jsonlite)
library(ggplot2)
})
EST_LEN <- 200
EST_GAP <- 30
# =====================================================================
# 1. Load and clean
# =====================================================================
returns <- read.csv("/app/data/stock_returns.csv")
recalls <- read.csv("/app/data/recalls.csv")
firms <- read.csv("/app/data/firms.csv")
returns <- returns[!is.na(returns$return) & !is.na(returns$market_return), ]
returns <- returns[!duplicated(returns), ]
returns$date <- as.Date(returns$date)
returns <- returns[order(returns$firm_id, returns$date), ]
rownames(returns) <- NULL
recalls <- recalls[!duplicated(recalls), ]
recalls$date <- as.Date(recalls$date)
firms <- firms[!duplicated(firms), ]
n_events <- nrow(recalls)
n_firms <- nrow(firms)
n_firms_with_recalls <- length(unique(recalls$firm_id))
all_dates <- sort(unique(returns$date))
date_to_idx <- setNames(seq_along(all_dates) - 1L, as.character(all_dates))
# =====================================================================
# 2. Market model , basic OLS, returns raw AR (no Patell standardization)
# =====================================================================
event_market_model <- function(fid, eidx) {
est_end <- eidx - EST_GAP - 1
est_start <- est_end - EST_LEN + 1
if (est_start < 0) return(NULL)
est_dates <- all_dates[(est_start + 1):(est_end + 1)]
sub <- returns[returns$firm_id == fid & returns$date %in% est_dates, ]
if (nrow(sub) < 100) return(NULL)
m <- lm(return ~ market_return, data = sub)
list(alpha = unname(coef(m)[1]), beta = unname(coef(m)[2]),
sigma_eps = sd(resid(m)), n_est = nrow(sub),
mean_rm = mean(sub$market_return),
sum_sq_dev_rm = sum((sub$market_return - mean(sub$market_return))^2))
}
windows <- list(w3 = c(-1, 1), w2 = c(0, 1), w11 = c(-5, 5))
event_rows <- list()
daily_long <- list()
for (i in seq_len(n_events)) {
fid <- recalls$firm_id[i]
edate <- recalls$date[i]
estr <- as.character(edate)
if (!(estr %in% names(date_to_idx))) next
eidx <- as.integer(date_to_idx[estr])
m <- event_market_model(fid, eidx)
if (is.null(m)) next
firm <- returns[returns$firm_id == fid, ]
rownames(firm) <- as.character(firm$date)
cars <- list(); ar_day0 <- NA_real_; valid_w3 <- TRUE
for (wname in names(windows)) {
w <- windows[[wname]]; ars <- numeric(0); ok <- TRUE
for (off in seq.int(w[1], w[2])) {
tidx <- eidx + off
if (tidx < 0 || tidx >= length(all_dates)) { ok <- FALSE; break }
target <- all_dates[tidx + 1]
if (!(as.character(target) %in% rownames(firm))) { ok <- FALSE; break }
rm_t <- firm[as.character(target), "market_return"]
ret_t <- firm[as.character(target), "return"]
ar <- ret_t - (m$alpha + m$beta * rm_t)
ars <- c(ars, ar)
if (wname == "w3" && off == 0) ar_day0 <- ar
}
if (!ok) {
if (wname == "w3") valid_w3 <- FALSE
cars[[wname]] <- NA_real_
} else {
# NOTE: simple summation of raw ARs , spec wants standardized SCAR
cars[[wname]] <- sum(ars)
}
}
if (!valid_w3 || is.na(cars$w3)) next
event_rows[[length(event_rows) + 1L]] <- data.frame(
event_id = as.integer(recalls$event_id[i]),
firm_id = fid,
date = estr,
scar_3day = cars$w3,
scar_2day = cars$w2,
scar_11day = cars$w11,
ar_day0 = ar_day0,
alpha_hat = m$alpha,
beta_hat = m$beta,
sigma_eps = m$sigma_eps,
n_est = m$n_est,
stringsAsFactors = FALSE
)
for (off in seq.int(-30L, 30L)) {
tidx <- eidx + off
if (tidx < 0 || tidx >= length(all_dates)) next
target <- all_dates[tidx + 1]
if (!(as.character(target) %in% rownames(firm))) next
daily_long[[length(daily_long) + 1L]] <- data.frame(
date = target, firm_id = fid,
ret = firm[as.character(target), "return"],
market_return = firm[as.character(target), "market_return"],
event_id =
…[truncated]cd /app && Rscript -e '
ip <- rownames(installed.packages())
for (p in c("jsonlite","ggplot2","sandwich","lmtest","MASS")) cat(p, p %in% ip, "\n")
' 2>&1jsonlite TRUE ggplot2 TRUE sandwich FALSE lmtest FALSE MASS TRUE
cd /app && Rscript -e '
returns <- read.csv("data/stock_returns.csv")
cat("rows:", nrow(returns), "\n")
cat("NA return:", sum(is.na(returns$return)), " NA mkt:", sum(is.na(returns$market_return)), "\n")
cat("sentinel (return < -10):", sum(returns$return < -10, na.rm=TRUE), "\n")
cat("dup rows:", sum(duplicated(returns)), "\n")
cat("unique firms:", length(unique(returns$firm_id)), "\n")
cat("date range:", min(returns$date), max(returns$date), "\n")
# per firm counts
tb <- table(returns$firm_id)
print(summary(as.integer(tb)))
cat("firms in returns:", length(tb), "\n")
' 2>&1rows: 9364 NA return: 0 NA mkt: 3 sentinel (return < -10): 5 dup rows: 4 unique firms: 18 date range: 2006-01-03 2007-12-31 Min. 1st Qu. Median Mean 3rd Qu. Max. 520.0 520.0 520.0 520.2 520.0 521.0 firms in returns: 18
cd /app && Rscript -e '
returns <- read.csv("data/stock_returns.csv")
# inspect sentinel values
print(returns[which(returns$return < -10),])
cat("--- check duplicates ---\n")
print(returns[duplicated(returns) | duplicated(returns, fromLast=TRUE),][1:8,])
cat("--- firms csv ---\n")
firms <- read.csv("data/firms.csv")
print(firms)
cat("any idio_vol 0 or NA:", any(firms$idio_vol==0), any(is.na(firms$idio_vol)), "\n")
' 2>&1firm_id date return market_return
1214 FIRM_015 2006-04-04 -99 0.044498
1554 FIRM_017 2006-10-27 -99 -0.007913
2270 FIRM_004 2006-02-08 -99 0.006117
7180 FIRM_006 2006-12-21 -99 0.002101
7332 FIRM_013 2006-01-10 -99 -0.035878
--- check duplicates ---
firm_id date return market_return
1026 FIRM_010 2007-05-18 0.024219 0.028165
1696 FIRM_018 2007-05-24 0.044480 0.049075
2927 FIRM_015 2007-05-03 -0.046116 -0.026444
4363 FIRM_015 2007-05-03 -0.046116 -0.026444
5780 FIRM_016 2007-01-22 -0.014105 -0.002825
6234 FIRM_010 2007-05-18 0.024219 0.028165
6279 FIRM_016 2007-01-22 -0.014105 -0.002825
7814 FIRM_018 2007-05-24 0.044480 0.049075
--- firms csv ---
firm_id market_cap_mm sic_code beta alpha idio_vol n_recalls
1 FIRM_001 2606.23 3944 1.0430 -0.000135 0.0152 4
2 FIRM_002 519.06 3944 0.6799 -0.000219 0.0187 2
3 FIRM_003 4449.48 3944 0.6878 -0.000038 0.0252 0
4 FIRM_004 5589.68 3942 1.4253 0.000847 0.0183 0
5 FIRM_005 173.95 3944 1.4716 -0.000333 0.0235 3
6 FIRM_006 378.94 3944 1.3716 0.000584 0.0180 0
7 FIRM_007 2107.82 3944 0.7672 -0.000741 0.0203 2
8 FIRM_008 1237.08 3942 1.2161 -0.000067 0.0162 3
9 FIRM_009 1771.95 3944 1.1583 0.000181 0.0155 0
10 FIRM_010 649.59 3942 1.2093 0.000393 0.0156 2
11 FIRM_011 5194.09 3942 1.5357 0.000456 0.0155 1
12 FIRM_012 4597.88 3944 1.2118 0.000497 0.0152 2
13 FIRM_013 1957.13 3944 1.4395 -0.000074 0.0219 4
14 FIRM_014 6993.17 3944 1.1338 -0.000131 0.0168 5
15 FIRM_015 3168.49 3942 1.2446 0.000529 0.0165 1
16 FIRM_016 644.74 3942 1.4156 0.000004 0.0187 2
17 FIRM_017 2814.39 3944 0.3714 -0.000538 0.0157 3
18 FIRM_018 572.12 3942 0.9402 -0.000467 0.0227 1
any idio_vol 0 or NA: FALSE FALSEcd /app && Rscript -e '
returns <- read.csv("data/stock_returns.csv")
recalls <- read.csv("data/recalls.csv")
returns <- returns[!is.na(returns$return) & !is.na(returns$market_return), ]
returns <- returns[returns$return >= -10, ] # sentinel
returns <- returns[!duplicated(returns), ]
returns$date <- as.Date(returns$date)
returns <- returns[order(returns$firm_id, returns$date), ]
recalls$date <- as.Date(recalls$date)
all_dates <- sort(unique(returns$date))
date_to_idx <- setNames(seq_along(all_dates)-1L, as.character(all_dates))
cat("n unique trading dates:", length(all_dates), "\n")
cat("n recall events:", nrow(recalls), "\n")
# check each event date in all_dates, and estimation feasibility
EST_LEN<-200; EST_GAP<-30
res <- data.frame()
for (i in seq_len(nrow(recalls))) {
estr <- as.character(recalls$date[i]); fid<-recalls$firm_id[i]
indate <- estr %in% names(date_to_idx)
eidx <- if(indate) as.integer(date_to_idx[estr]) else NA
est_end <- if(indate) eidx-EST_GAP-1 else NA
est_start <- if(indate) est_end-EST_LEN+1 else NA
# count firm obs in est window
nest<-NA
if(indate && !is.na(est_start) && est_start>=0){
est_dates<-all_dates[(est_start+1):(est_end+1)]
nest<-sum(returns$firm_id==fid & returns$date %in% est_dates)
}
res<-rbind(res,data.frame(event_id=recalls$event_id[i],fid=fid,date=estr,indate=indate,eidx=eidx,est_start=est_start,nest=nest))
}
print(res)
cat("events with date in panel:", sum(res$indate), "\n")
cat("events est_start>=0:", sum(res$est_start>=0, na.rm=TRUE), "\n")
cat("events nest>=100:", sum(res$nest>=100, na.rm=TRUE), "\n")
' 2>&1n unique trading dates: 520 n recall events: 35 event_id fid date indate eidx est_start nest 1 1 FIRM_007 2007-03-21 TRUE 316 86 200 2 2 FIRM_002 2007-03-28 TRUE 321 91 200 3 3 FIRM_017 2007-04-16 TRUE 334 104 199 4 4 FIRM_013 2007-04-20 TRUE 338 108 200 5 5 FIRM_014 2007-04-24 TRUE 340 110 200 6 6 FIRM_013 2007-05-04 TRUE 348 118 200 7 7 FIRM_012 2007-05-08 TRUE 350 120 200 8 8 FIRM_014 2007-05-16 TRUE 356 126 200 9 9 FIRM_001 2007-05-24 TRUE 362 132 200 10 10 FIRM_016 2007-05-30 TRUE 366 136 200 11 11 FIRM_014 2007-05-31 TRUE 367 137 200 12 12 FIRM_014 2007-06-13 TRUE 376 146 200 13 13 FIRM_008 2007-06-14 TRUE 377 147 200 14 14 FIRM_015 2007-06-15 TRUE 378 148 200 15 15 FIRM_007 2007-06-20 TRUE 381 151 200 16 16 FIRM_001 2007-06-25 TRUE 384 154 200 17 17 FIRM_017 2007-07-09 TRUE 394 164 199 18 18 FIRM_005 2007-07-13 TRUE 398 168 200 19 19 FIRM_002 2007-07-23 TRUE 404 174 200 20 20 FIRM_012 2007-08-09 TRUE 417 187 200 21 21 FIRM_005 2007-08-10 TRUE 418 188 200 22 22 FIRM_016 2007-08-13 TRUE 419 189 200 23 23 FIRM_008 2007-08-14 TRUE 420 190 200 24 24 FIRM_001 2007-08-21 TRUE 425 195 200 25 25 FIRM_018 2007-08-27 TRUE 429 199 200 26 26 FIRM_010 2007-09-04 TRUE 435 205 200 27 27 FIRM_005 2007-09-07 TRUE 438 208 200 28 28 FIRM_013 2007-09-18 TRUE 445 215 200 29 29 FIRM_010 2007-09-20 TRUE 447 217 200 30 30 FIRM_001 2007-09-25 TRUE 450 220 200 31 31 FIRM_014 2007-09-27 TRUE 452 222 200 32 32 FIRM_008 2007-11-07 TRUE 481 251 200 33 33 FIRM_013 2007-11-08 TRUE 482 252 200 34 34 FIRM_017 2007-11-09 TRUE 483 253 200 35 35 FIRM_011 2007-11-13 TRUE 485 255 200 events with date in panel: 35 events est_start>=0: 35 events nest>=100: 35
cd /app && Rscript -e '
returns <- read.csv("data/stock_returns.csv")
recalls <- read.csv("data/recalls.csv")
returns <- returns[!is.na(returns$return) & !is.na(returns$market_return), ]
returns <- returns[returns$return >= -10, ]
returns <- returns[!duplicated(returns), ]
returns$date <- as.Date(returns$date); recalls$date <- as.Date(recalls$date)
returns <- returns[order(returns$firm_id, returns$date), ]
all_dates <- sort(unique(returns$date))
date_to_idx <- setNames(seq_along(all_dates)-1L, as.character(all_dates))
D <- length(all_dates)
chk <- function(fid, eidx, offs){
fdates <- as.character(returns$date[returns$firm_id==fid])
all(sapply(offs, function(o){ t<-eidx+o; if(t<0||t>=D) return(FALSE); as.character(all_dates[t+1]) %in% fdates }))
}
w3<- -1:1; w2<-0:1; w11<- -5:5
r<-data.frame()
for(i in seq_len(nrow(recalls))){
estr<-as.character(recalls$date[i]); fid<-recalls$firm_id[i]
eidx<-as.integer(date_to_idx[estr])
r<-rbind(r,data.frame(event_id=recalls$event_id[i],
w3=chk(fid,eidx,w3), w2=chk(fid,eidx,w2), w11=chk(fid,eidx,w11),
n_corrado=sum(sapply(-30:30,function(o){t<-eidx+o; if(t<0||t>=D)return(FALSE); as.character(all_dates[t+1]) %in% as.character(returns$date[returns$firm_id==fid])}))))
}
cat("events complete w3:",sum(r$w3)," w2:",sum(r$w2)," w11:",sum(r$w11),"\n")
print(table(r$w11))
cat("corrado window day counts summary:\n"); print(summary(r$n_corrado))
print(r[!r$w11 | !r$w3,])
' 2>&1events complete w3: 35 w2: 35 w11: 35
TRUE
35
corrado window day counts summary:
Min. 1st Qu. Median Mean 3rd Qu. Max.
61 61 61 61 61 61
[1] event_id w3 w2 w11 n_corrado
<0 rows> (or 0-length row.names)cd /app && Rscript -e '
returns <- read.csv("data/stock_returns.csv")
returns <- returns[!is.na(returns$return) & !is.na(returns$market_return), ]
returns <- returns[returns$return >= -10, ]
returns <- returns[!duplicated(returns), ]
# is market_return constant within date?
agg <- aggregate(market_return ~ date, data=returns, FUN=function(x) length(unique(round(x,8))))
cat("max distinct market_return per date:", max(agg$market_return), "\n")
cat("dates total:", nrow(agg), "\n")
' 2>&1max distinct market_return per date: 1 dates total: 520
command: create
path: /app/analysis.R
file_text: suppressPackageStartupMessages({
library(jsonlite)
library(ggplot2)
})
EST_LEN <- 200
EST_GAP <- 30
# =====================================================================
# 1. Load and clean
# - drop NA return / market_return
# - drop sentinel returns (return < -10)
# - drop duplicate rows
# - sort by (firm_id, date)
# =====================================================================
returns <- read.csv("/app/data/stock_returns.csv")
recalls <- read.csv("/app/data/recalls.csv")
firms <- read.csv("/app/data/firms.csv")
returns <- returns[!is.na(returns$return) & !is.na(returns$market_return), ]
returns <- returns[returns$return >= -10, ] # remove sentinel returns
returns <- returns[!duplicated(returns), ]
returns$date <- as.Date(returns$date)
returns <- returns[order(returns$firm_id, returns$date), ]
rownames(returns) <- NULL
recalls <- recalls[!duplicated(recalls), ]
recalls$date <- as.Date(recalls$date)
recalls <- recalls[order(recalls$event_id), ]
firms <- firms[!duplicated(firms), ]
n_events <- nrow(recalls)
n_firms <- nrow(firms)
n_firms_with_recalls <- length(unique(recalls$firm_id))
all_dates <- sort(unique(returns$date))
date_to_idx <- setNames(seq_along(all_dates) - 1L, as.character(all_dates))
D <- length(all_dates)
# market return is identical across firms within a date (market index)
mkt_by_date <- tapply(returns$market_return, as.character(returns$date), function(x) x[1])
# per-firm return tables with date rownames for fast lookup
firm_tabs <- list()
for (fid in unique(returns$firm_id)) {
sub <- returns[returns$firm_id == fid, c("date", "return", "market_return")]
rownames(sub) <- as.character(sub$date)
firm_tabs[[fid]] <- sub
}
# =====================================================================
# 2. Market model (OLS) on the 200-day estimation window ending
# EST_GAP+1 days before the event. Returns the quantities needed for
# Patell / BMP prediction-error-corrected standardization.
# =====================================================================
event_market_model <- function(fid, eidx) {
est_end <- eidx - EST_GAP - 1
est_start <- est_end - EST_LEN + 1
if (est_start < 0) return(NULL)
est_dates <- all_dates[(est_start + 1):(est_end + 1)]
sub <- firm_tabs[[fid]]
sub <- sub[as.character(est_dates)[as.character(est_dates) %in% rownames(sub)], ]
if (nrow(sub) < 100) return(NULL)
m <- lm(return ~ market_return, data = sub)
list(alpha = unname(coef(m)[1]), beta = unname(coef(m)[2]),
sigma_eps = sd(resid(m)), n_est = nrow(sub),
mean_rm = mean(sub$market_return),
sum_sq_dev_rm = sum((sub$market_return - mean(sub$market_return))^2))
}
windows <- list(w3 = c(-1, 1), w2 = c(0, 1), w11 = c(-5, 5))
# Prediction-error-corrected standard deviation of a CAR (BMP / Patell):
# Var(CAR) = sigma^2 * [ k + k^2/L + (sum_t (Rm_t - Rm_bar))^2 / SSx ]
scar_sd <- function(m, rm_vec) {
k <- length(rm_vec)
m$sigma_eps * sqrt(k + k^2 / m$n_est +
(sum(rm_vec - m$mean_rm))^2 / m$sum_sq_dev_rm)
}
event_rows <- list()
for (i in seq_len(n_events)) {
fid <- recalls$firm_id[i]
edate <- recalls$date[i]
estr <- as.character(edate)
if (!(estr %in% names(date_to_idx))) next
if (is.null(firm_tabs[[fid]])) next
eidx <- as.integer(date_to_idx[estr])
m <- event_market_model(fid, eidx)
if (is.null(m)) next
firm <- firm_tabs[[fid]]
scars <- list(); ar_day0 <- NA_real_; valid_w3 <- TRUE
for (wname in names(windows)) {
w <- windows[[wname]]; ars <- numeric(0); rms <- numeric(0); ok <- TRUE
for (off in seq.int(w[1], w[2])) {
tidx <- eidx + off
if (tidx < 0 || tidx >= D) { ok <- FALSE; break }
target <- as.character(all_dates[tidx + 1])
if (!(target %in% rownames(firm))) { ok <- FALSE; break }
rm_t <- firm[target, "market_return"]
ret_t <- firm[target, "return"]
ar <- ret_t - (m$alpha
…[truncated]Existing file was successfully overwritten at /app/analysis.R
cd /app && rm -f outputs/* && Rscript analysis.R 2>&1
Done. n_valid_events = 35 rho_bar = 0.0057 hac_lag = 3 cal n_days = 230
cd /app && cat outputs/event_study_results.json
{
"n_events": 35,
"n_firms": 18,
"n_firms_with_recalls": 14,
"n_valid_events": 35,
"rho_bar": 0.005682,
"aggregate_scars": {
"window_3day": {
"mean_scar": -1.010063,
"patell_z": -5.975613,
"bmp_t": -4.999555,
"kp_t": -4.576949,
"pct_negative": 0.828571,
"n": 35
},
"window_2day": {
"mean_scar": -0.863089,
"patell_z": -5.106103,
"bmp_t": -4.514831,
"kp_t": -4.133197,
"pct_negative": 0.8,
"n": 35
},
"window_11day": {
"mean_scar": -0.44071,
"patell_z": -2.607278,
"bmp_t": -2.175112,
"kp_t": -1.991252,
"pct_negative": 0.628571,
"n": 35
}
},
"cross_section_hac": {
"intercept": 6.838785,
"log_units": -0.275669,
"media": -0.139352,
"severity": -0.048921,
"log_mcap": -0.349169,
"se_intercept": 1.979508,
"se_log_units": 0.143233,
"se_media": 0.045219,
"se_severity": 0.079398,
"se_log_mcap": 0.108871,
"r_squared": 0.365058,
"n_obs": 35,
"hac_lag": 3
},
"cross_section_wls": {
"intercept": 6.151918,
"log_units": -0.243832,
"media": -0.14227,
"severity": -0.068431,
"log_mcap": -0.301541,
"se_intercept": 2.368191,
"se_log_units": 0.119652,
"se_media": 0.062864,
"se_severity": 0.074063,
"se_log_mcap": 0.191579,
"r_squared": 0.307122,
"n_obs": 35
},
"calendar_time": {
"alpha": -0.000858,
"beta": 1.033203,
"t_alpha": -1.34566,
"p_value": 0.179749,
"n_days": 230
},
"corrado_rank": {
"z_stat": -2.426518,
"p_value": 0.015244
},
"cowan_sign": {
"z_stat": 0.253547,
"p_value": 0.799846,
"p_bar": 0.492859,
"frac_positive": 0.514286
},
"schipper_thompson": {
"wald_stat": 25.701792,
"wald_p": 1.1e-05,
"df": 3
}
}cd /app && head -6 outputs/event_cars.csv && echo "..." && wc -l outputs/event_cars.csv && echo "--- col means ---" && Rscript -e '
d<-read.csv("outputs/event_cars.csv"); cat("rows:",nrow(d),"\n")
cat("mean scar_3day:",mean(d$scar_3day)," scar_2day:",mean(d$scar_2day)," scar_11day:",mean(d$scar_11day),"\n")
cat("range ar_day0:",range(d$ar_day0),"\n")
cat("any NA:",sum(is.na(d)),"\n")'"event_id","firm_id","date","scar_3day","scar_2day","scar_11day","ar_day0" 1,"FIRM_007","2007-03-21",-2.76865580230164,-2.03141834065309,-2.69698090609601,-0.0188048397516721 2,"FIRM_002","2007-03-28",1.64522745954583,2.19420109305874,1.39928236980868,0.0513410791394269 3,"FIRM_017","2007-04-16",0.943542716595015,1.03149633499138,1.46978343118227,0.00560955526504031 4,"FIRM_013","2007-04-20",-0.276256178300222,-0.623811706667714,-0.833731582190839,-0.0130106860489592 5,"FIRM_014","2007-04-24",-0.932289729110778,-0.478689086519495,-0.867726261472249,0.00353526947807872 ... 36 outputs/event_cars.csv --- col means --- rows: 35 mean scar_3day: -1.010063 scar_2day: -0.863089 scar_11day: -0.4407104 range ar_day0: -0.04559815 0.05134108 any NA: 0
cd /app && Rscript -e '
suppressPackageStartupMessages(library(jsonlite))
returns <- read.csv("data/stock_returns.csv"); recalls<-read.csv("data/recalls.csv")
returns <- returns[!is.na(returns$return)&!is.na(returns$market_return),]
returns <- returns[returns$return>=-10,]; returns<-returns[!duplicated(returns),]
returns$date<-as.Date(returns$date); recalls$date<-as.Date(recalls$date)
returns<-returns[order(returns$firm_id,returns$date),]
all_dates<-sort(unique(returns$date)); idx<-setNames(seq_along(all_dates)-1L,as.character(all_dates))
# Event 1: FIRM_007, 2007-03-21
fid<-"FIRM_007"; eidx<-as.integer(idx["2007-03-21"])
est_end<-eidx-31; est_start<-est_end-199
est_dates<-all_dates[(est_start+1):(est_end+1)]
sub<-returns[returns$firm_id==fid & returns$date %in% est_dates,]
m<-lm(return~market_return,data=sub)
a<-coef(m)[1]; b<-coef(m)[2]; sig<-sd(resid(m)); L<-nrow(sub)
rmbar<-mean(sub$market_return); SSx<-sum((sub$market_return-rmbar)^2)
cat("n_est",L,"alpha",a,"beta",b,"sigma",sig,"\n")
firm<-returns[returns$firm_id==fid,]; rownames(firm)<-as.character(firm$date)
# 3-day window
ar<-c(); rm<-c()
for(off in -1:1){ t<-as.character(all_dates[eidx+off+1]); ar<-c(ar,firm[t,"return"]-(a+b*firm[t,"market_return"])); rm<-c(rm,firm[t,"market_return"]) }
k<-3; car<-sum(ar)
sdc<-sig*sqrt(k+k^2/L+(sum(rm-rmbar))^2/SSx)
cat("CAR_3",car," SCAR_3",car/sdc," (expected -2.768656)\n")
cat("ar_day0",ar[2]," (expected -0.0188048)\n")
' 2>&1n_est 200 alpha -0.002097156 beta 0.7896948 sigma 0.01988566 CAR_3 -0.09607672 SCAR_3 -2.768656 (expected -2.768656) ar_day0 -0.01880484 (expected -0.0188048)
cd /app && Rscript -e '
suppressPackageStartupMessages(library(jsonlite))
res<-fromJSON("outputs/event_cars.csv")
cs<-read.csv("outputs/event_cars.csv")
recalls<-read.csv("data/recalls.csv"); firms<-read.csv("data/firms.csv")
cs<-merge(cs,recalls[,c("event_id","units_recalled","media_articles","severity_score")],by="event_id")
cs<-merge(cs,firms[,c("firm_id","market_cap_mm","idio_vol")],by="firm_id")
cs$log_units<-log(cs$units_recalled); cs$log_mcap<-log(cs$market_cap_mm)
cs<-cs[order(cs$event_id),]
mod<-lm(scar_3day~log_units+media_articles+severity_score+log_mcap,data=cs)
X<-model.matrix(mod); e<-resid(mod); N<-nrow(X); k<-ncol(X)
Binv<-solve(crossprod(X))
# independent Newey-West via weighted autocovariance of scores u_t = x_t e_t
u<-X*e
NW<-function(Lh){
S<-crossprod(u) # lag 0
if(Lh>=1) for(l in 1:Lh){ w<-1-l/(Lh+1); Gl<-t(u[(l+1):N,,drop=F])%*%u[1:(N-l),,drop=F]; S<-S+w*(Gl+t(Gl)) }
sqrt(diag(Binv%*%S%*%Binv))
}
cat("HAC L=3:\n"); print(round(NW(3),6))
cat("HC0 (L=0) vs lm OLS SE:\n")
print(round(NW(0),6)); print(round(summary(mod)$coefficients[,2],6))
cat("Andrews L for N=35:",floor(4*(N/100)^(2/9)),"\n")
' 2>&1Error in parse_con(txt, bigint_as_char) : parse error: trailing garbage
"event_id","firm_id","date","scar_3day","
(right here) ------^
Calls: fromJSON -> parse_and_simplify -> parseJSON -> parse_con
Execution haltedcd /app && Rscript -e '
cs<-read.csv("outputs/event_cars.csv")
recalls<-read.csv("data/recalls.csv"); firms<-read.csv("data/firms.csv")
cs<-merge(cs,recalls[,c("event_id","units_recalled","media_articles","severity_score")],by="event_id")
cs<-merge(cs,firms[,c("firm_id","market_cap_mm","idio_vol")],by="firm_id")
cs$log_units<-log(cs$units_recalled); cs$log_mcap<-log(cs$market_cap_mm)
cs<-cs[order(cs$event_id),]
mod<-lm(scar_3day~log_units+media_articles+severity_score+log_mcap,data=cs)
X<-model.matrix(mod); e<-resid(mod); N<-nrow(X); k<-ncol(X)
Binv<-solve(crossprod(X)); u<-X*e
NW<-function(Lh){ S<-crossprod(u); if(Lh>=1) for(l in 1:Lh){ w<-1-l/(Lh+1); Gl<-t(u[(l+1):N,,drop=F])%*%u[1:(N-l),,drop=F]; S<-S+w*(Gl+t(Gl)) }; sqrt(diag(Binv%*%S%*%Binv)) }
cat("HAC L=3 (independent recompute):\n"); print(round(NW(3),6))
cat("HC0(L=0):",round(NW(0),6),"\n")
cat("lm OLS SE:",round(summary(mod)$coefficients[,2],6),"\n")
' 2>&1HAC L=3 (independent recompute):
(Intercept) log_units media_articles severity_score log_mcap
1.979508 0.143233 0.045219 0.079398 0.108871
HC0(L=0): 1.610718 0.113315 0.049211 0.062449 0.133549
lm OLS SE: 2.186625 0.116774 0.059732 0.07054 0.167618cd /app && Rscript -e '
returns <- read.csv("data/stock_returns.csv")
returns <- returns[!is.na(returns$return)&!is.na(returns$market_return),]
returns <- returns[returns$return>=-10,]; returns<-returns[!duplicated(returns),]
returns$date<-as.Date(returns$date); returns<-returns[order(returns$firm_id,returns$date),]
# rho_bar recompute
fr<-list()
for(f in unique(returns$firm_id)){ s<-returns[returns$firm_id==f,]; if(nrow(s)<30) next
mm<-lm(return~market_return,data=s); fr[[f]]<-setNames(resid(mm),as.character(s$date)) }
nm<-names(fr); cors<-c(); np<-0
for(i in 1:(length(nm)-1)) for(j in (i+1):length(nm)){
com<-intersect(names(fr[[nm[i]]]),names(fr[[nm[j]]])); if(length(com)<20) next
cors<-c(cors,cor(fr[[nm[i]]][com],fr[[nm[j]]][com])); np<-np+1 }
cat("n firms in rho:",length(nm)," n pairs:",np," rho_bar:",round(mean(cors),6),"\n")
cat("range of pair cors:",round(range(cors),4),"\n")
' 2>&1n firms in rho: 18 n pairs: 153 rho_bar: 0.005682 range of pair cors: -0.1027 0.1196
cd /app && Rscript -e '
d<-read.csv("outputs/event_cars.csv")
M<-as.matrix(d[,c("scar_3day","scar_2day","scar_11day")])
mbar<-colMeans(M); S<-cov(M); N<-nrow(M)
W<-as.numeric(N*t(mbar)%*%solve(S)%*%mbar)
cat("Schipper-Thompson Wald:",round(W,6)," p:",signif(1-pchisq(W,3),4),"\n")
cat("mbar:",round(mbar,4),"\n")
# Corrado cross-check: aggregate K mean/sd
' 2>&1Schipper-Thompson Wald: 25.70179 p: 1.101e-05 mbar: -1.0101 -0.8631 -0.4407
cd /app && ls -la outputs/ && file outputs/*.png
total 158 drwxrws--- 2 h2tagent h2tagent 4096 Jun 20 18:01 . drwxrws--- 4 h2tagent h2tagent 4096 Jun 20 18:01 .. -rw-r--r-- 1 h2tagent h2tagent 50557 Jun 20 18:01 car_timeline.png -rw-r--r-- 1 h2tagent h2tagent 3625 Jun 20 18:01 event_cars.csv -rw-r--r-- 1 h2tagent h2tagent 1838 Jun 20 18:01 event_study_results.json -rw-r--r-- 1 h2tagent h2tagent 96024 Jun 20 18:01 portfolio_comparison.png [stderr] bash: file: command not found
command: view path: /app/outputs/car_timeline.png
<output_image> …[truncated]
cd /app && Rscript -e 'cat(as.character(packageVersion("ggplot2")),"\n")'3.4.1
command: str_replace
path: /app/analysis.R
old_str: x = "Trading days relative to recall announcement (day 0)",
y = "Average cumulative abnormal return") +
theme_minimal(base_size = 12)
ggsave("/app/outputs/car_timeline.png", p1, width = 8, height = 5, dpi = 120)
new_str: x = "Trading days relative to recall announcement (day 0)",
y = "Average cumulative abnormal return") +
theme_minimal(base_size = 12) +
theme(plot.background = element_rect(fill = "white", color = NA),
panel.background = element_rect(fill = "white", color = NA))
ggsave("/app/outputs/car_timeline.png", p1, width = 8, height = 5, dpi = 120, bg = "white")The file /app/analysis.R has been edited successfully.
command: str_replace
path: /app/analysis.R
old_str: x = "Date", y = "Cumulative simple return", color = "Series") +
theme_minimal(base_size = 12) +
theme(legend.position = "bottom")
ggsave("/app/outputs/portfolio_comparison.png", p2, width = 10, height = 5, dpi = 120)
new_str: x = "Date", y = "Cumulative simple return", color = "Series") +
theme_minimal(base_size = 12) +
theme(legend.position = "bottom",
plot.background = element_rect(fill = "white", color = NA),
panel.background = element_rect(fill = "white", color = NA))
ggsave("/app/outputs/portfolio_comparison.png", p2, width = 10, height = 5, dpi = 120, bg = "white")The file /app/analysis.R has been edited successfully.
cd /app && rm -f outputs/* && Rscript analysis.R 2>&1 | tail -2
Done. n_valid_events = 35 rho_bar = 0.0057 hac_lag = 3 cal n_days = 230
command: view path: /app/outputs/car_timeline.png
<output_image> …[truncated]
command: view path: /app/outputs/portfolio_comparison.png
<output_image> …[truncated]
command: str_replace path: /app/analysis.R old_str: events_by_firm <- split(event_df$eidx, event_df$firm_id) cal_rows <- list() new_str: # portfolio membership is based on recall announcements (calendar-time method # does not need a market-model estimation window); map each recall to its # trading-day index. rec_idx <- recalls[as.character(recalls$date) %in% names(date_to_idx), ] rec_idx$eidx <- as.integer(date_to_idx[as.character(rec_idx$date)]) events_by_firm <- split(rec_idx$eidx, rec_idx$firm_id) cal_rows <- list()
The file /app/analysis.R has been edited successfully.
cd /app && rm -f outputs/* && Rscript analysis.R 2>&1 | tail -2 && echo "---" && Rscript -e 'library(jsonlite); j<-fromJSON("outputs/event_study_results.json"); cat("calendar_time:\n"); print(unlist(j$calendar_time))'Done. n_valid_events = 35 rho_bar = 0.0057 hac_lag = 3 cal n_days = 230
---
calendar_time:
alpha beta t_alpha p_value n_days
-0.000858 1.033203 -1.345660 0.179749 230.000000cd /app && Rscript -e '
returns <- read.csv("data/stock_returns.csv"); recalls<-read.csv("data/recalls.csv")
returns <- returns[!is.na(returns$return)&!is.na(returns$market_return),]
returns <- returns[returns$return>=-10,]; returns<-returns[!duplicated(returns),]
returns$date<-as.Date(returns$date); recalls$date<-as.Date(recalls$date)
returns<-returns[order(returns$firm_id,returns$date),]
all_dates<-sort(unique(returns$date)); idx<-setNames(seq_along(all_dates)-1L,as.character(all_dates)); D<-length(all_dates)
ft<-list(); for(f in unique(returns$firm_id)){s<-returns[returns$firm_id==f,c("date","return","market_return")];rownames(s)<-as.character(s$date);ft[[f]]<-s}
raw<-function(w){ cars<-c(); for(i in 1:nrow(recalls)){ fid<-recalls$firm_id[i]; eidx<-as.integer(idx[as.character(recalls$date[i])])
ee<-eidx-31; es<-ee-199; ed<-all_dates[(es+1):(ee+1)]; sub<-returns[returns$firm_id==fid&returns$date%in%ed,]; m<-lm(return~market_return,data=sub); a<-coef(m)[1];b<-coef(m)[2]
ar<-c(); ok<-T; for(o in w[1]:w[2]){t<-as.character(all_dates[eidx+o+1]); if(!(t%in%rownames(ft[[fid]]))){ok<-F;break}; ar<-c(ar,ft[[fid]][t,"return"]-(a+b*ft[[fid]][t,"market_return"]))}
if(ok) cars<-c(cars,sum(ar)) }; cars }
c3<-raw(c(-1,1)); c2<-raw(c(0,1)); c11<-raw(c(-5,5))
cat(sprintf("Raw mean CAR 3-day: %.4f (%.2f%%), median %.4f, min %.4f\n",mean(c3),100*mean(c3),median(c3),min(c3)))
cat(sprintf("Raw mean CAR 2-day: %.4f (%.2f%%)\n",mean(c2),100*mean(c2)))
cat(sprintf("Raw mean CAR 11-day:%.4f (%.2f%%)\n",mean(c11),100*mean(c11)))
cat(sprintf("Annualized calendar alpha approx: %.2f%% (daily -0.000858 * 252)\n",100*-0.000858*252))
' 2>&1Raw mean CAR 3-day: -0.0292 (-2.92%), median -0.0277, min -0.0961 Raw mean CAR 2-day: -0.0205 (-2.05%) Raw mean CAR 11-day:-0.0250 (-2.50%) Annualized calendar alpha approx: -21.62% (daily -0.000858 * 252)
cd /app && Rscript -e '
firms<-read.csv("data/firms.csv")
cat(sprintf("median mcap: %.0f mm, mean: %.0f mm\n",median(firms$market_cap_mm),mean(firms$market_cap_mm)))
cat(sprintf("dollar loss at -2.9%% on median firm: %.0f mm\n",0.029*median(firms$market_cap_mm)))
# cross-section t-stats (HAC)
b<-c(intercept=6.838785,log_units=-0.275669,media=-0.139352,severity=-0.048921,log_mcap=-0.349169)
se<-c(1.979508,0.143233,0.045219,0.079398,0.108871)
cat("HAC t-stats:\n"); print(round(b/se,2))
'median mcap: 2032 mm, mean: 2524 mm
dollar loss at -2.9% on median firm: 59 mm
HAC t-stats:
intercept log_units media severity log_mcap
3.45 -1.92 -3.08 -0.62 -3.21command: create path: /app/outputs/research_memo.md file_text: # Research Memo: The Stock-Market Impact of Toy Product Recalls **To:** Regulatory policy and investment strategy readers **From:** Financial Economics / Event-Study Desk **Re:** What happens to a toy manufacturer's share price when it announces a product recall? **Method in one line:** For 35 recall announcements we measured each firm's "abnormal" return , the portion of its stock move that cannot be explained by the overall market , and then tested, in several independent ways, whether those abnormal moves are systematically different from zero. ## 1. How big is the hit, and is it real? The answer is unambiguous: recall announcements destroy shareholder value quickly and significantly. In the three trading days bracketing the announcement (the day before, the day of, and the day after), the average firm lost about **2.9%** of its market value beyond what the market did, and in the tighter two-day announcement window (day 0 and day +1) about **2.0%**. For a median toy maker in this sample (roughly $2.0 billion in market capitalization) a 2.9% drop is about **$59 million of equity value erased in three days.** These effects are highly statistically significant, not flukes. Using standardized abnormal returns, the Patell z-statistic is about **−6.0** for the three-day window and **−5.1** for the two-day window (values beyond roughly ±2 are already significant at the 5% level). The results survive two more demanding tests that guard against a handful of volatile firms driving the average (the Boehmer-Musumeci-Poulsen t ≈ **−5.0**) and against events moving together in time (the Kolari-Pynnönen t ≈ **−4.6**). Roughly **83%** of individual recalls produced negative abnormal returns. A joint test across all three windows simultaneously (Schipper-Thompson) overwhelmingly rejects the hypothesis of "no effect" (χ² ≈ **25.7**, p < 0.0001). The wider eleven-day window [−5,+5] also averages about −2.5% but is noisier (z ≈ −2.6): widening the window adds unrelated price movement without adding signal, which itself tells us the reaction is concentrated right at the announcement, as the event-time chart (`car_timeline.png`) shows , a flat line before day 0 and a sharp step down afterward. ## 2. Which recalls hurt the most? Not all recalls are equal. A cross-sectional regression (with HAC/Newey-West standard errors) explains about **37%** of the variation in the three-day reaction and points to three drivers: - **Media coverage is the single most powerful predictor** (t ≈ −3.1): each additional news article is associated with a more negative reaction. Press attention amplifies reputational damage, signals the breadth of consumer awareness, and raises the expected hit to future demand. - **Firm size matters** (t ≈ −3.2): larger firms show *more* negative standardized reactions. Part of this is mechanical , larger firms have lower idiosyncratic volatility, so a given percentage loss represents more "standard deviations" of surprise , and part is economic: bigger toy brands have more reputational capital and more product lines exposed to contagion. - **Recall scale** (log units recalled) is marginally significant (t ≈ −1.9): bigger recalls imply larger remediation and liability costs. - Strikingly, the engineered **severity score is not significant** (t ≈ −0.6). Once media attention and scale are accounted for, the hazard classification adds little , investors appear to price *salience and quantity* more than the official severity label. A weighted regression (weighting by each firm's return precision) produces the same signs and conclusions, so these findings are not an artifact of a few noisy firms. ## 3. Short-window drop vs. long-run drift The calendar-time portfolio , which holds every firm that had a recall within the prior/following thirty trading days and measures its alpha , shows only a small, **statistically insignificant** abnormal return (about −0.09% per day, …[truncated]
New file created successfully at /app/outputs/research_memo.md
cd /app && wc -w outputs/research_memo.md && echo "words above"
1051 outputs/research_memo.md words above
cd /app && rm -f outputs/* && Rscript analysis.R >/dev/null 2>&1 && cp outputs/event_study_results.json /tmp/run1.json && cp outputs/event_cars.csv /tmp/run1.csv && rm -f outputs/* && Rscript analysis.R >/dev/null 2>&1 && diff /tmp/run1.json outputs/event_study_results.json && echo "JSON identical across runs" && diff /tmp/run1.csv outputs/event_cars.csv && echo "CSV identical across runs" && echo "--- files ---" && ls -la outputs/
JSON identical across runs CSV identical across runs --- files --- total 157 drwxrws--- 2 h2tagent h2tagent 4096 Jun 20 18:05 . drwxrws--- 4 h2tagent h2tagent 4096 Jun 20 18:03 .. -rw-r--r-- 1 h2tagent h2tagent 53112 Jun 20 18:05 car_timeline.png -rw-r--r-- 1 h2tagent h2tagent 3625 Jun 20 18:05 event_cars.csv -rw-r--r-- 1 h2tagent h2tagent 1838 Jun 20 18:05 event_study_results.json -rw-r--r-- 1 h2tagent h2tagent 92237 Jun 20 18:05 portfolio_comparison.png
command: str_replace
path: /app/analysis.R
old_str: } else {
car <- sum(ars)
sdc <- scar_sd(m, rms)
scars[[wname]] <- car / sdc # standardized CAR
}
}
if (!valid_w3 || is.na(scars$w3)) next
event_rows[[length(event_rows) + 1L]] <- data.frame(
event_id = as.integer(recalls$event_id[i]),
firm_id = fid,
date = estr,
eidx = eidx,
scar_3day = scars$w3,
scar_2day = scars$w2,
scar_11day = scars$w11,
ar_day0 = ar_day0,
new_str: } else {
car <- sum(ars)
sdc <- scar_sd(m, rms)
scars[[wname]] <- car / sdc # standardized CAR
raw_cars[[wname]] <- car # raw (non-standardized) CAR
}
}
if (!valid_w3 || is.na(scars$w3)) next
event_rows[[length(event_rows) + 1L]] <- data.frame(
event_id = as.integer(recalls$event_id[i]),
firm_id = fid,
date = estr,
eidx = eidx,
scar_3day = scars$w3,
scar_2day = scars$w2,
scar_11day = scars$w11,
raw_car_3 = raw_cars$w3,
raw_car_2 = raw_cars$w2,
raw_car_11 = raw_cars$w11,
ar_day0 = ar_day0,The file /app/analysis.R has been edited successfully.
command: str_replace path: /app/analysis.R old_str: scars <- list(); ar_day0 <- NA_real_; valid_w3 <- TRUE new_str: scars <- list(); raw_cars <- list(w3 = NA_real_, w2 = NA_real_, w11 = NA_real_) ar_day0 <- NA_real_; valid_w3 <- TRUE
The file /app/analysis.R has been edited successfully.
command: str_replace
path: /app/analysis.R
old_str: cat("Done. n_valid_events =", n_valid_events,
new_str: # =====================================================================
# Research memo (generated from the computed results, no hardcoding)
# =====================================================================
raw3 <- mean(event_df$raw_car_3, na.rm = TRUE)
raw2 <- mean(event_df$raw_car_2, na.rm = TRUE)
raw11 <- mean(event_df$raw_car_11, na.rm = TRUE)
med_mcap <- median(firms$market_cap_mm, na.rm = TRUE)
dollar_loss <- abs(raw3) * med_mcap
t_units <- cs_hac$log_units / cs_hac$se_log_units
t_media <- cs_hac$media / cs_hac$se_media
t_sev <- cs_hac$severity / cs_hac$se_severity
t_mcap <- cs_hac$log_mcap / cs_hac$se_log_mcap
sig <- function(p) if (is.finite(p) && p < 0.05) "statistically significant" else "statistically insignificant"
dir3 <- if (agg_3$mean_scar < 0) "negative" else "positive"
pm <- function(x) sprintf("%+.2f%%", 100 * x)
f2 <- function(x) sprintf("%.2f", x)
cal_ann <- 100 * calendar$alpha * 252
memo <- paste0(
"# Research Memo: The Stock-Market Impact of Toy Product Recalls\n\n",
"**To:** Regulatory policy and investment strategy readers \n",
"**From:** Financial Economics / Event-Study Desk \n",
"**Re:** What happens to a toy manufacturer's share price when it announces a product recall?\n\n",
"**Method in one line:** For ", n_valid_events, " recall announcements (", n_firms_with_recalls,
" firms) we measured each firm's *abnormal* return -- the part of its stock move not explained by ",
"the overall market, estimated from a 200-day window ending 30 days before each event -- and tested, ",
"in several independent ways, whether those abnormal moves differ systematically from zero.\n\n",
"## 1. How big is the hit, and is it real?\n\n",
"The reaction is ", dir3, " and economically meaningful. In the three trading days bracketing the ",
"announcement the average firm's abnormal return was about **", pm(raw3), "**, and in the two-day ",
"announcement window (day 0 and day +1) about **", pm(raw2), "**. For a median toy maker in this sample ",
"(about $", formatC(med_mcap, format = "f", digits = 0, big.mark = ","), " million in market value), ",
"a ", pm(raw3), " move is roughly **$", formatC(dollar_loss, format = "f", digits = 0, big.mark = ","),
" million of equity value** repriced within three days.\n\n",
"These effects are highly significant. The standardized mean abnormal return (SCAR) is ", f2(agg_3$mean_scar),
" for the three-day window with a Patell z of **", f2(agg_3$patell_z), "** (values beyond about +/-2 are ",
"significant at 5%). The finding survives tougher tests that absorb firm-specific volatility ",
"(Boehmer-Musumeci-Poulsen t = **", f2(agg_3$bmp_t), "**) and cross-event correlation ",
"(Kolari-Pynnonen t = **", f2(agg_3$kp_t), "**, using an average residual correlation rho-bar = ",
f2(rho_bar), "). About **", sprintf("%.0f%%", 100 * agg_3$pct_negative), "** of individual recalls produced ",
"negative abnormal returns. A joint test across all three windows (Schipper-Thompson) rejects the ",
"no-effect null overwhelmingly (chi-square = **", f2(schipper$wald_stat), "**, p = ",
formatC(schipper$wald_p, format = "g", digits = 2), ", df = 3). The wider eleven-day window averages ",
pm(raw11), " (z = ", f2(agg_11$patell_z), ") but is noisier: widening the window adds unrelated price ",
"movement without adding signal, confirming the reaction is concentrated at the announcement, exactly ",
"as the event-time chart (`car_timeline.png`) shows -- flat before day 0, a sharp step down after.\n\n",
"## 2. Which recalls hurt the most?\n\n",
"A cross-sectional regression of the three-day SCAR on recall and firm characteristics (Newey-West/HAC ",
"standard errors, lag = ", cs_hac$hac_lag, ") explains about **", sprintf("%.0f%%", 100 * cs_hac$r_squared),
"** of the variation and points to these drivers:\n\n",
"- **Media coverage** (t = ", f2(t_media), "): more press is associated with a
…[truncated]The file /app/analysis.R has been edited successfully.
cd /app && rm -f outputs/* && Rscript analysis.R 2>&1 | tail -2 && echo "--- outputs ---" && ls outputs/ && echo "--- memo words ---" && wc -w outputs/research_memo.md && echo "--- csv header ---" && head -1 outputs/event_cars.csv
Done. n_valid_events = 35 rho_bar = 0.0057 hac_lag = 3 cal n_days = 230 --- outputs --- car_timeline.png event_cars.csv event_study_results.json portfolio_comparison.png research_memo.md --- memo words --- 1006 outputs/research_memo.md --- csv header --- "event_id","firm_id","date","scar_3day","scar_2day","scar_11day","ar_day0"
cd /app && sed -n '1,20p' outputs/research_memo.md
# Research Memo: The Stock-Market Impact of Toy Product Recalls **To:** Regulatory policy and investment strategy readers **From:** Financial Economics / Event-Study Desk **Re:** What happens to a toy manufacturer's share price when it announces a product recall? **Method in one line:** For 35 recall announcements (14 firms) we measured each firm's *abnormal* return -- the part of its stock move not explained by the overall market, estimated from a 200-day window ending 30 days before each event -- and tested, in several independent ways, whether those abnormal moves differ systematically from zero. ## 1. How big is the hit, and is it real? The reaction is negative and economically meaningful. In the three trading days bracketing the announcement the average firm's abnormal return was about **-2.92%**, and in the two-day announcement window (day 0 and day +1) about **-2.05%**. For a median toy maker in this sample (about $2,032 million in market value), a -2.92% move is roughly **$59 million of equity value** repriced within three days. These effects are highly significant. The standardized mean abnormal return (SCAR) is -1.01 for the three-day window with a Patell z of **-5.98** (values beyond about +/-2 are significant at 5%). The finding survives tougher tests that absorb firm-specific volatility (Boehmer-Musumeci-Poulsen t = **-5.00**) and cross-event correlation (Kolari-Pynnonen t = **-4.58**, using an average residual correlation rho-bar = 0.01). About **83%** of individual recalls produced negative abnormal returns. A joint test across all three windows (Schipper-Thompson) rejects the no-effect null overwhelmingly (chi-square = **25.70**, p = 1.1e-05, df = 3). The wider eleven-day window averages -2.50% (z = -2.61) but is noisier: widening the window adds unrelated price movement without adding signal, confirming the reaction is concentrated at the announcement, exactly as the event-time chart (`car_timeline.png`) shows -- flat before day 0, a sharp step down after. ## 2. Which recalls hurt the most? A cross-sectional regression of the three-day SCAR on recall and firm characteristics (Newey-West/HAC standard errors, lag = 3) explains about **37%** of the variation and points to these drivers: - **Media coverage** (t = -3.08): more press is associated with a more negative reaction. Media amplifies reputational damage, signals how widely consumers are aware of the problem, and raises the expected hit to future demand. - **Firm size** (log market cap, t = -3.21): larger firms show more negative *standardized* reactions. Part is mechanical -- larger firms have lower idiosyncratic volatility, so a given percentage loss is a larger number of standard deviations -- and part is economic, as bigger brands have more reputational capital and more product lines exposed to contagion.
command: str_replace
path: /app/analysis.R
old_str: "(Kolari-Pynnonen t = **", f2(agg_3$kp_t), "**, using an average residual correlation rho-bar = ",
f2(rho_bar), "). About **", sprintf("%.0f%%", 100 * agg_3$pct_negative), "** of individual recalls produced ",
new_str: "(Kolari-Pynnonen t = **", f2(agg_3$kp_t), "**, using an average residual correlation rho-bar = ",
sprintf("%.3f", rho_bar), "). About **", sprintf("%.0f%%", 100 * agg_3$pct_negative), "** of individual recalls produced ",The file /app/analysis.R has been edited successfully.
cd /app && rm -f outputs/* && Rscript analysis.R 2>&1 | tail -1 && Rscript -e '
library(jsonlite); j<-fromJSON("outputs/event_study_results.json", simplifyVector=FALSE)
# expected schema
exp <- list(
top=c("n_events","n_firms","n_firms_with_recalls","n_valid_events","rho_bar","aggregate_scars","cross_section_hac","cross_section_wls","calendar_time","corrado_rank","cowan_sign","schipper_thompson"),
win=c("mean_scar","patell_z","bmp_t","kp_t","pct_negative","n"),
hac=c("intercept","log_units","media","severity","log_mcap","se_intercept","se_log_units","se_media","se_severity","se_log_mcap","r_squared","n_obs","hac_lag"),
wls=c("intercept","log_units","media","severity","log_mcap","se_intercept","se_log_units","se_media","se_severity","se_log_mcap","r_squared","n_obs"),
cal=c("alpha","beta","t_alpha","p_value","n_days"),
cor=c("z_stat","p_value"), cow=c("z_stat","p_value","p_bar","frac_positive"), st=c("wald_stat","wald_p","df"))
chk<-function(have,want,nm){ miss<-setdiff(want,have); ext<-setdiff(have,want); cat(sprintf("%-18s ok=%s", nm, length(miss)==0&&length(ext)==0)); if(length(miss))cat(" MISSING:",miss); if(length(ext))cat(" EXTRA:",ext); cat("\n")}
chk(names(j),exp$top,"top")
for(w in c("window_3day","window_2day","window_11day")) chk(names(j$aggregate_scars[[w]]),exp$win,w)
chk(names(j$cross_section_hac),exp$hac,"hac")
chk(names(j$cross_section_wls),exp$wls,"wls")
chk(names(j$calendar_time),exp$cal,"calendar")
chk(names(j$corrado_rank),exp$cor,"corrado")
chk(names(j$cowan_sign),exp$cow,"cowan")
chk(names(j$schipper_thompson),exp$st,"schipper")
cat("\nTypes: n_events int?",is.integer(j$n_events)||j$n_events==as.integer(j$n_events),
" df=3?",j$schipper_thompson$df==3," hac_lag=",j$cross_section_hac$hac_lag,"\n")
'Done. n_valid_events = 35 rho_bar = 0.0057 hac_lag = 3 cal n_days = 230 top ok=TRUE window_3day ok=TRUE window_2day ok=TRUE window_11day ok=TRUE hac ok=TRUE wls ok=TRUE calendar ok=TRUE corrado ok=TRUE cowan ok=TRUE schipper ok=TRUE Types: n_events int? TRUE df=3? TRUE hac_lag= 3
cd /app && echo "--- prohibited pkgs / randomness ---" && grep -nEi "eventstudies|estudy2|EventStudy|RcppEventStudy|sandwich|lmtest|set\.seed|rnorm|runif|sample\(|boot" analysis.R || echo "NONE found (good)" && echo "--- library calls ---" && grep -n "library(" analysis.R--- prohibited pkgs / randomness --- NONE found (good) --- library calls --- 2: library(jsonlite) 3: library(ggplot2)
cd /app && sed -n '1,130p' analysis.R
suppressPackageStartupMessages({
library(jsonlite)
library(ggplot2)
})
EST_LEN <- 200
EST_GAP <- 30
# =====================================================================
# 1. Load and clean
# - drop NA return / market_return
# - drop sentinel returns (return < -10)
# - drop duplicate rows
# - sort by (firm_id, date)
# =====================================================================
returns <- read.csv("/app/data/stock_returns.csv")
recalls <- read.csv("/app/data/recalls.csv")
firms <- read.csv("/app/data/firms.csv")
returns <- returns[!is.na(returns$return) & !is.na(returns$market_return), ]
returns <- returns[returns$return >= -10, ] # remove sentinel returns
returns <- returns[!duplicated(returns), ]
returns$date <- as.Date(returns$date)
returns <- returns[order(returns$firm_id, returns$date), ]
rownames(returns) <- NULL
recalls <- recalls[!duplicated(recalls), ]
recalls$date <- as.Date(recalls$date)
recalls <- recalls[order(recalls$event_id), ]
firms <- firms[!duplicated(firms), ]
n_events <- nrow(recalls)
n_firms <- nrow(firms)
n_firms_with_recalls <- length(unique(recalls$firm_id))
all_dates <- sort(unique(returns$date))
date_to_idx <- setNames(seq_along(all_dates) - 1L, as.character(all_dates))
D <- length(all_dates)
# market return is identical across firms within a date (market index)
mkt_by_date <- tapply(returns$market_return, as.character(returns$date), function(x) x[1])
# per-firm return tables with date rownames for fast lookup
firm_tabs <- list()
for (fid in unique(returns$firm_id)) {
sub <- returns[returns$firm_id == fid, c("date", "return", "market_return")]
rownames(sub) <- as.character(sub$date)
firm_tabs[[fid]] <- sub
}
# =====================================================================
# 2. Market model (OLS) on the 200-day estimation window ending
# EST_GAP+1 days before the event. Returns the quantities needed for
# Patell / BMP prediction-error-corrected standardization.
# =====================================================================
event_market_model <- function(fid, eidx) {
est_end <- eidx - EST_GAP - 1
est_start <- est_end - EST_LEN + 1
if (est_start < 0) return(NULL)
est_dates <- all_dates[(est_start + 1):(est_end + 1)]
sub <- firm_tabs[[fid]]
sub <- sub[as.character(est_dates)[as.character(est_dates) %in% rownames(sub)], ]
if (nrow(sub) < 100) return(NULL)
m <- lm(return ~ market_return, data = sub)
list(alpha = unname(coef(m)[1]), beta = unname(coef(m)[2]),
sigma_eps = sd(resid(m)), n_est = nrow(sub),
mean_rm = mean(sub$market_return),
sum_sq_dev_rm = sum((sub$market_return - mean(sub$market_return))^2))
}
windows <- list(w3 = c(-1, 1), w2 = c(0, 1), w11 = c(-5, 5))
# Prediction-error-corrected standard deviation of a CAR (BMP / Patell):
# Var(CAR) = sigma^2 * [ k + k^2/L + (sum_t (Rm_t - Rm_bar))^2 / SSx ]
scar_sd <- function(m, rm_vec) {
k <- length(rm_vec)
m$sigma_eps * sqrt(k + k^2 / m$n_est +
(sum(rm_vec - m$mean_rm))^2 / m$sum_sq_dev_rm)
}
event_rows <- list()
for (i in seq_len(n_events)) {
fid <- recalls$firm_id[i]
edate <- recalls$date[i]
estr <- as.character(edate)
if (!(estr %in% names(date_to_idx))) next
if (is.null(firm_tabs[[fid]])) next
eidx <- as.integer(date_to_idx[estr])
m <- event_market_model(fid, eidx)
if (is.null(m)) next
firm <- firm_tabs[[fid]]
scars <- list(); raw_cars <- list(w3 = NA_real_, w2 = NA_real_, w11 = NA_real_)
ar_day0 <- NA_real_; valid_w3 <- TRUE
for (wname in names(windows)) {
w <- windows[[wname]]; ars <- numeric(0); rms <- numeric(0); ok <- TRUE
for (off in seq.int(w[1], w[2])) {
tidx <- eidx + off
if (tidx < 0 || tidx >= D) { ok <- FALSE; break }
target <- as.character(all_dates[tidx + 1])
if (!(target %in% rownames(firm))) { ok <- FALSE; break }
rm_t <- firm[target, "market_return"]
ret_t <- firm[target, "return"]
ar <- r
…[truncated]cd /app && sed -n '130,220p' analysis.R
scar_2day = scars$w2,
scar_11day = scars$w11,
raw_car_3 = raw_cars$w3,
raw_car_2 = raw_cars$w2,
raw_car_11 = raw_cars$w11,
ar_day0 = ar_day0,
alpha_hat = m$alpha,
beta_hat = m$beta,
sigma_eps = m$sigma_eps,
n_est = m$n_est,
stringsAsFactors = FALSE
)
}
event_df <- do.call(rbind, event_rows)
n_valid_events <- nrow(event_df)
# =====================================================================
# 3. rho_bar : mean pairwise correlation of per-firm market-model
# residuals, fitted once on each firm's entire cleaned panel.
# =====================================================================
firm_resid <- list()
for (fid in names(firm_tabs)) {
sub <- firm_tabs[[fid]]
if (nrow(sub) < 30) next # drop firms with < 30 obs
mm <- lm(return ~ market_return, data = sub)
firm_resid[[fid]] <- setNames(resid(mm), rownames(sub))
}
rf_names <- names(firm_resid)
pair_cors <- c()
if (length(rf_names) >= 2) {
for (a in 1:(length(rf_names) - 1)) {
for (b in (a + 1):length(rf_names)) {
ra <- firm_resid[[rf_names[a]]]; rb <- firm_resid[[rf_names[b]]]
common <- intersect(names(ra), names(rb))
if (length(common) < 20) next # require >= 20 overlap
pair_cors <- c(pair_cors, cor(ra[common], rb[common]))
}
}
}
rho_bar <- if (length(pair_cors) > 0) mean(pair_cors) else 0.0
# =====================================================================
# Aggregate tests on the cross-section of SCARs for each window.
# =====================================================================
aggregate_scar <- function(vals) {
vals <- vals[!is.na(vals)]
n <- length(vals)
if (n < 2) return(list(mean_scar = NA_real_, patell_z = NA_real_,
bmp_t = NA_real_, kp_t = NA_real_,
pct_negative = NA_real_, n = 0L))
mean_v <- mean(vals)
var_v <- var(vals) # ddof = 1
sd_v <- sqrt(var_v)
patell <- sum(vals) / sqrt(n) # Patell z
bmp <- mean_v / (sd_v / sqrt(n)) # BMP t
kp <- mean_v / sqrt(var_v * (1 + (n - 1) * rho_bar) / n) # Kolari-Pynnonen
list(mean_scar = mean_v, patell_z = patell, bmp_t = bmp, kp_t = kp,
pct_negative = mean(vals < 0), n = as.integer(n))
}
agg_3 <- aggregate_scar(event_df$scar_3day)
agg_2 <- aggregate_scar(event_df$scar_2day)
agg_11 <- aggregate_scar(event_df$scar_11day)
# =====================================================================
# 4. Cross-sectional OLS with Newey-West (Bartlett) HAC standard errors.
# =====================================================================
cs <- merge(event_df,
recalls[, c("event_id", "units_recalled",
"media_articles", "severity_score")], by = "event_id")
cs <- merge(cs, firms[, c("firm_id", "market_cap_mm", "idio_vol")], by = "firm_id")
cs$log_units <- log(cs$units_recalled)
cs$log_mcap <- log(cs$market_cap_mm)
cs <- cs[order(cs$event_id), ]
rownames(cs) <- NULL
cs_model <- lm(scar_3day ~ log_units + media_articles + severity_score + log_mcap,
data = cs)
ols_summary <- summary(cs_model)
X <- model.matrix(cs_model)
e <- as.numeric(residuals(cs_model))
Nh <- nrow(X); k <- ncol(X)
XtX_inv <- solve(crossprod(X))
L_hac <- floor(4 * (Nh / 100)^(2 / 9)) # Andrews (1991) rule
S <- matrix(0, k, k)
for (t in seq_len(Nh)) S <- S + (e[t]^2) * tcrossprod(X[t, ])
if (L_hac >= 1) {
for (l in 1:L_hac) {
w_l <- 1 - l / (L_hac + 1) # Bartlett kernelcd /app && rm -f outputs/* && Rscript analysis.R 2>&1 | tail -1 && echo "--- final outputs ---" && ls -la outputs/ && echo "--- memo word count ---" && wc -w outputs/research_memo.md
Done. n_valid_events = 35 rho_bar = 0.0057 hac_lag = 3 cal n_days = 230 --- final outputs --- total 163 drwxrws--- 2 h2tagent h2tagent 4096 Jun 20 18:07 . drwxrws--- 4 h2tagent h2tagent 4096 Jun 20 18:06 .. -rw-r--r-- 1 h2tagent h2tagent 53112 Jun 20 18:07 car_timeline.png -rw-r--r-- 1 h2tagent h2tagent 3625 Jun 20 18:07 event_cars.csv -rw-r--r-- 1 h2tagent h2tagent 1838 Jun 20 18:07 event_study_results.json -rw-r--r-- 1 h2tagent h2tagent 92237 Jun 20 18:07 portfolio_comparison.png -rw-r--r-- 1 h2tagent h2tagent 6531 Jun 20 18:07 research_memo.md --- memo word count --- 1006 outputs/research_memo.md
command: view path: /app/outputs/portfolio_comparison.png
<output_image> …[truncated]
cd /app && rm -rf outputs && Rscript analysis.R 2>&1 | tail -1 && cp outputs/event_study_results.json /tmp/final1.json && rm -rf outputs && Rscript analysis.R >/dev/null 2>&1 && diff /tmp/final1.json outputs/event_study_results.json && echo "DETERMINISTIC + recreates missing dir" && ls outputs/ | sort
Done. n_valid_events = 35 rho_bar = 0.0057 hac_lag = 3 cal n_days = 230 DETERMINISTIC + recreates missing dir car_timeline.png event_cars.csv event_study_results.json portfolio_comparison.png research_memo.md
cd /app && cat outputs/event_study_results.json
{
"n_events": 35,
"n_firms": 18,
"n_firms_with_recalls": 14,
"n_valid_events": 35,
"rho_bar": 0.005682,
"aggregate_scars": {
"window_3day": {
"mean_scar": -1.010063,
"patell_z": -5.975613,
"bmp_t": -4.999555,
"kp_t": -4.576949,
"pct_negative": 0.828571,
"n": 35
},
"window_2day": {
"mean_scar": -0.863089,
"patell_z": -5.106103,
"bmp_t": -4.514831,
"kp_t": -4.133197,
"pct_negative": 0.8,
"n": 35
},
"window_11day": {
"mean_scar": -0.44071,
"patell_z": -2.607278,
"bmp_t": -2.175112,
"kp_t": -1.991252,
"pct_negative": 0.628571,
"n": 35
}
},
"cross_section_hac": {
"intercept": 6.838785,
"log_units": -0.275669,
"media": -0.139352,
"severity": -0.048921,
"log_mcap": -0.349169,
"se_intercept": 1.979508,
"se_log_units": 0.143233,
"se_media": 0.045219,
"se_severity": 0.079398,
"se_log_mcap": 0.108871,
"r_squared": 0.365058,
"n_obs": 35,
"hac_lag": 3
},
"cross_section_wls": {
"intercept": 6.151918,
"log_units": -0.243832,
"media": -0.14227,
"severity": -0.068431,
"log_mcap": -0.301541,
"se_intercept": 2.368191,
"se_log_units": 0.119652,
"se_media": 0.062864,
"se_severity": 0.074063,
"se_log_mcap": 0.191579,
"r_squared": 0.307122,
"n_obs": 35
},
"calendar_time": {
"alpha": -0.000858,
"beta": 1.033203,
"t_alpha": -1.34566,
"p_value": 0.179749,
"n_days": 230
},
"corrado_rank": {
"z_stat": -2.426518,
"p_value": 0.015244
},
"cowan_sign": {
"z_stat": 0.253547,
"p_value": 0.799846,
"p_bar": 0.492859,
"frac_positive": 0.514286
},
"schipper_thompson": {
"wald_stat": 25.701792,
"wald_p": 1.1e-05,
"df": 3
}
}No file changes, the agent left the workspace untouched.
# SyncVals normalized verifier summary
# task: product-recall-stock-price-event
# attempt: 8 status: completed raw_score: 1.0
# reward rule: binary: score 1.0 == 1.0
# => reward = 1.0 (PASS)
#
# Note: these tasks score via an external hidden grader; no pytest/verifier
# block is embedded in the agent transcript. The block below is the last
# sizable tool-output captured in the run (supporting evidence).
----------------------------------------------------------------------
{
"n_events": 35,
"n_firms": 18,
"n_firms_with_recalls": 14,
"n_valid_events": 35,
"rho_bar": 0.005682,
"aggregate_scars": {
"window_3day": {
"mean_scar": -1.010063,
"patell_z": -5.975613,
"bmp_t": -4.999555,
"kp_t": -4.576949,
"pct_negative": 0.828571,
"n": 35
},
"window_2day": {
"mean_scar": -0.863089,
"patell_z": -5.106103,
"bmp_t": -4.514831,
"kp_t": -4.133197,
"pct_negative": 0.8,
"n": 35
},
"window_11day": {
"mean_scar": -0.44071,
"patell_z": -2.607278,
"bmp_t": -2.175112,
"kp_t": -1.991252,
"pct_negative": 0.628571,
"n": 35
}
},
"cross_section_hac": {
"intercept": 6.838785,
"log_units": -0.275669,
"media": -0.139352,
"severity": -0.048921,
"log_mcap": -0.349169,
"se_intercept": 1.979508,
"se_log_units": 0.143233,
"se_media": 0.045219,
"se_severity": 0.079398,
"se_log_mcap": 0.108871,
"r_squared": 0.365058,
"n_obs": 35,
"hac_lag": 3
},
"cross_section_wls": {
"intercept": 6.151918,
"log_units": -0.243832,
"media": -0.14227,
"severity": -0.068431,
"log_mcap": -0.301541,
"se_intercept": 2.368191,
"se_log_units": 0.119652,
"se_media": 0.062864,
"se_severity": 0.074063,
"se_log_mcap": 0.191579,
"r_squared": 0.307122,
"n_obs": 35
},
"calendar_time": {
"alpha": -0.000858,
"beta": 1.033203,
"t_alpha": -1.34566,
"p_value": 0.179749,
"n_days": 230
},
"corrado_rank": {
"z_stat": -2.426518,
"p_value": 0.015244
},
"cowan_sign": {
"z_stat": 0.253547,
"p_value": 0.799846,
"p_bar": 0.492859,
"frac_positive": 0.514286
},
"schipper_thompson": {
"wald_stat": 25.701792,
"wald_p": 1.1e-05,
"df": 3
}
}Reproduce this trial: git checkout 2f94510 && PYTHONPATH=src python3 scripts/build_site.py , then open trial/trial_dfeedb695a3d4e2c. Re-running the agent live requires EVAL_PLATFORM_ENABLE_OAUTH_SMOKE=1 and is non-deterministic.
Trial trial_dfeedb695a3d4e2c · verifier authoritative; classifier explanatory.