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===" && head -5 data/stock_returns.csv && echo "..." && wc -l data/stock_returns.csv && echo "===RECALLS===" && head -5 data/recalls.csv && wc -l data/recalls.csv && echo "===FIRMS===" && head -5 data/firms.csv && wc -l data/firms.csv
===STOCK RETURNS=== 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=== 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=== 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 '
returns <- read.csv("/app/data/stock_returns.csv")
cat("Total rows:", nrow(returns), "\n")
cat("NA return:", sum(is.na(returns$return)), "\n")
cat("NA market_return:", sum(is.na(returns$market_return)), "\n")
cat("Sentinel return < -10:", sum(returns$return < -10, na.rm=TRUE), "\n")
cat("Duplicated rows:", sum(duplicated(returns)), "\n")
cat("Unique firms:", length(unique(returns$firm_id)), "\n")
cat("Date range:", min(returns$date), max(returns$date), "\n")
print(summary(returns$return))
cat("--- firms with returns ---\n")
print(sort(unique(returns$firm_id)))
'Total rows: 9364
NA return: 0
NA market_return: 3
Sentinel return < -10: 5
Duplicated rows: 4
Unique firms: 18
Date range: 2006-01-03 2007-12-31
Min. 1st Qu. Median Mean 3rd Qu. Max.
-99.00000 -0.02424 -0.00124 -0.05390 0.02130 0.14049
--- firms with returns ---
[1] "FIRM_001" "FIRM_002" "FIRM_003" "FIRM_004" "FIRM_005" "FIRM_006"
[7] "FIRM_007" "FIRM_008" "FIRM_009" "FIRM_010" "FIRM_011" "FIRM_012"
[13] "FIRM_013" "FIRM_014" "FIRM_015" "FIRM_016" "FIRM_017" "FIRM_018"cd /app && Rscript -e '
returns <- read.csv("/app/data/stock_returns.csv")
# sentinel check
cat("Rows with return < -10:\n")
print(returns[which(returns$return < -10),])
cat("\nNA rows:\n")
print(returns[which(is.na(returns$market_return)),])
cat("\nDuplicated rows:\n")
print(returns[which(duplicated(returns) | duplicated(returns, fromLast=TRUE)),])
# After cleaning how many per firm
returns2 <- returns[!is.na(returns$return) & !is.na(returns$market_return), ]
returns2 <- returns2[returns2$return >= -10, ]
returns2 <- returns2[!duplicated(returns2), ]
cat("\nAfter cleaning rows:", nrow(returns2), "\n")
print(table(returns2$firm_id))
'Rows with return < -10:
firm_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
NA rows:
firm_id date return market_return
4393 FIRM_015 2007-10-24 0.046806 NA
4502 FIRM_010 2007-11-12 0.029817 NA
8160 FIRM_010 2006-06-08 0.011398 NA
Duplicated rows:
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
After cleaning rows: 9352
FIRM_001 FIRM_002 FIRM_003 FIRM_004 FIRM_005 FIRM_006 FIRM_007 FIRM_008
520 520 520 519 520 519 520 520
FIRM_009 FIRM_010 FIRM_011 FIRM_012 FIRM_013 FIRM_014 FIRM_015 FIRM_016
520 518 520 520 519 520 518 520
FIRM_017 FIRM_018
519 520cd /app && Rscript -e '
returns <- read.csv("/app/data/stock_returns.csv")
recalls <- read.csv("/app/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)
all_dates <- sort(unique(returns$date))
cat("Unique dates (union calendar):", length(all_dates), "\n")
cat("Recall event count:", nrow(recalls), "\n")
recalls$date <- as.Date(recalls$date)
cat("Recall date range:", as.character(min(recalls$date)), as.character(max(recalls$date)), "\n")
date_to_idx <- setNames(seq_along(all_dates) - 1L, as.character(all_dates))
# Check which events are in the calendar and have enough estimation window
for (i in seq_len(nrow(recalls))) {
estr <- as.character(recalls$date[i])
inc <- estr %in% names(date_to_idx)
idx <- if (inc) as.integer(date_to_idx[estr]) else NA
cat(sprintf("event %2d firm %s date %s inCal=%s idx=%s estStart=%s\n",
recalls$event_id[i], recalls$firm_id[i], estr, inc, idx,
if(!is.na(idx)) idx-30-1-200+1 else NA))
}
'Unique dates (union calendar): 520 Recall event count: 35 Recall date range: 2007-03-21 2007-11-13 event 1 firm FIRM_007 date 2007-03-21 inCal=TRUE idx=316 estStart=86 event 2 firm FIRM_002 date 2007-03-28 inCal=TRUE idx=321 estStart=91 event 3 firm FIRM_017 date 2007-04-16 inCal=TRUE idx=334 estStart=104 event 4 firm FIRM_013 date 2007-04-20 inCal=TRUE idx=338 estStart=108 event 5 firm FIRM_014 date 2007-04-24 inCal=TRUE idx=340 estStart=110 event 6 firm FIRM_013 date 2007-05-04 inCal=TRUE idx=348 estStart=118 event 7 firm FIRM_012 date 2007-05-08 inCal=TRUE idx=350 estStart=120 event 8 firm FIRM_014 date 2007-05-16 inCal=TRUE idx=356 estStart=126 event 9 firm FIRM_001 date 2007-05-24 inCal=TRUE idx=362 estStart=132 event 10 firm FIRM_016 date 2007-05-30 inCal=TRUE idx=366 estStart=136 event 11 firm FIRM_014 date 2007-05-31 inCal=TRUE idx=367 estStart=137 event 12 firm FIRM_014 date 2007-06-13 inCal=TRUE idx=376 estStart=146 event 13 firm FIRM_008 date 2007-06-14 inCal=TRUE idx=377 estStart=147 event 14 firm FIRM_015 date 2007-06-15 inCal=TRUE idx=378 estStart=148 event 15 firm FIRM_007 date 2007-06-20 inCal=TRUE idx=381 estStart=151 event 16 firm FIRM_001 date 2007-06-25 inCal=TRUE idx=384 estStart=154 event 17 firm FIRM_017 date 2007-07-09 inCal=TRUE idx=394 estStart=164 event 18 firm FIRM_005 date 2007-07-13 inCal=TRUE idx=398 estStart=168 event 19 firm FIRM_002 date 2007-07-23 inCal=TRUE idx=404 estStart=174 event 20 firm FIRM_012 date 2007-08-09 inCal=TRUE idx=417 estStart=187 event 21 firm FIRM_005 date 2007-08-10 inCal=TRUE idx=418 estStart=188 event 22 firm FIRM_016 date 2007-08-13 inCal=TRUE idx=419 estStart=189 event 23 firm FIRM_008 date 2007-08-14 inCal=TRUE idx=420 estStart=190 event 24 firm FIRM_001 date 2007-08-21 inCal=TRUE idx=425 estStart=195 event 25 firm FIRM_018 date 2007-08-27 inCal=TRUE idx=429 estStart=199 event 26 firm FIRM_010 date 2007-09-04 inCal=TRUE idx=435 estStart=205 event 27 firm FIRM_005 date 2007-09-07 inCal=TRUE idx=438 estStart=208 event 28 firm FIRM_013 date 2007-09-18 inCal=TRUE idx=445 estStart=215 event 29 firm FIRM_010 date 2007-09-20 inCal=TRUE idx=447 estStart=217 event 30 firm FIRM_001 date 2007-09-25 inCal=TRUE idx=450 estStart=220 event 31 firm FIRM_014 date 2007-09-27 inCal=TRUE idx=452 estStart=222 event 32 firm FIRM_008 date 2007-11-07 inCal=TRUE idx=481 estStart=251 event 33 firm FIRM_013 date 2007-11-08 inCal=TRUE idx=482 estStart=252 event 34 firm FIRM_017 date 2007-11-09 inCal=TRUE idx=483 estStart=253 event 35 firm FIRM_011 date 2007-11-13 inCal=TRUE idx=485 estStart=255
cd /app && Rscript -e '
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, ]
returns <- returns[!duplicated(returns), ]
# market_return constant per 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("market_return min/max:", range(returns$market_return), "\n")
cat("n unique recall firms:", length(unique(recalls$firm_id)), "\n")
cat("n firms rows:", nrow(firms), " idio_vol NAs:", sum(is.na(firms$idio_vol)), "\n")
cat("idio_vol range:", range(firms$idio_vol), " any zero:", any(firms$idio_vol==0), "\n")
cat("firms in firms.csv but not returns:", setdiff(firms$firm_id, returns$firm_id), "\n")
cat("recall firms not in firms.csv:", setdiff(recalls$firm_id, firms$firm_id), "\n")
cat("units_recalled range:", range(recalls$units_recalled), " any <=0:", any(recalls$units_recalled<=0),"\n")
cat("dup event_ids:", anyDuplicated(recalls$event_id), "\n")
'Max distinct market_return per date: 1 market_return min/max: -0.073813 0.073147 n unique recall firms: 14 n firms rows: 18 idio_vol NAs: 0 idio_vol range: 0.0152 0.0252 any zero: FALSE firms in firms.csv but not returns: recall firms not in firms.csv: units_recalled range: 67821 19715949 any <=0: FALSE dup event_ids: 0
cd /app && Rscript -e '
pkgs <- c("jsonlite","ggplot2","sandwich","lmtest","MASS")
for (p in pkgs) cat(sprintf("%-10s %s\n", p, requireNamespace(p, quietly=TRUE)))
' 2>&1jsonlite TRUE ggplot2 TRUE sandwich FALSE lmtest FALSE MASS TRUE
cd /app && Rscript -e '
returns <- read.csv("/app/data/stock_returns.csv")
recalls <- read.csv("/app/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))
EST_LEN<-200; EST_GAP<-30
nest <- c()
for (i in seq_len(nrow(recalls))) {
estr <- as.character(recalls$date[i]); eidx <- as.integer(date_to_idx[estr])
est_end <- eidx-EST_GAP-1; est_start <- est_end-EST_LEN+1
est_dates <- all_dates[(est_start+1):(est_end+1)]
sub <- returns[returns$firm_id==recalls$firm_id[i] & returns$date %in% est_dates,]
nest <- c(nest, nrow(sub))
}
cat("n_est range:", range(nest), " min:", min(nest), " all>=100:", all(nest>=100), "\n")
cat("n events:", nrow(recalls), "\n")
'n_est range: 199 200 min: 199 all>=100: TRUE n events: 35
cd /app && Rscript -e 'cat("ggplot2:", as.character(packageVersion("ggplot2")), "\n"); cat("R:", as.character(getRversion()), "\n")'ggplot2: 3.4.1 R: 4.2.2
command: create
path: /app/analysis.R
file_text: suppressPackageStartupMessages({
library(jsonlite)
library(ggplot2)
})
# =====================================================================
# Product Recall Stock-Price Event Study
# Deterministic modern event-study pipeline (base/statistical primitives)
# =====================================================================
EST_LEN <- 200 # estimation-window length (trading days)
EST_GAP <- 30 # gap (trading days) between estimation window and event
round6 <- function(x) if (is.numeric(x) && !is.integer(x)) round(x, 6) else x
rlist <- function(l) lapply(l, round6)
# =====================================================================
# 1. Load and clean
# - drop NAs, sentinel returns (return < -10), duplicates
# - sort by (firm_id, date)
# =====================================================================
returns <- read.csv("/app/data/stock_returns.csv", stringsAsFactors = FALSE)
recalls <- read.csv("/app/data/recalls.csv", stringsAsFactors = FALSE)
firms <- read.csv("/app/data/firms.csv", stringsAsFactors = FALSE)
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))
# Global trading-day calendar (union of all firm dates), 0-based index
all_dates <- sort(unique(returns$date))
n_dates <- length(all_dates)
date_to_idx <- setNames(seq_along(all_dates) - 1L, as.character(all_dates))
# Per-firm fast lookups: named numeric vectors keyed by date string
firm_ids <- sort(unique(returns$firm_id))
firm_data <- list(); ret_vec <- list(); mkt_vec <- list()
for (f in firm_ids) {
d <- returns[returns$firm_id == f, c("date", "return", "market_return")]
d <- d[order(d$date), ]
firm_data[[f]] <- d
ret_vec[[f]] <- setNames(d$return, as.character(d$date))
mkt_vec[[f]] <- setNames(d$market_return, as.character(d$date))
}
# Market return by date (constant across firms on a given date)
mkt_by_date <- tapply(returns$market_return, as.character(returns$date), function(x) x[1])
# =====================================================================
# 2. Market model + prediction-error-corrected SAR / SCAR
# =====================================================================
# Estimation window: 200 trading days ending 30 trading days before event,
# i.e. calendar indices [eidx-EST_GAP-EST_LEN, eidx-EST_GAP-1]. Require >=100 obs.
event_market_model <- function(fid, eidx) {
est_end <- eidx - EST_GAP - 1L
est_start <- est_end - EST_LEN + 1L
if (est_start < 0) return(NULL)
est_dates <- as.character(all_dates[(est_start + 1L):(est_end + 1L)])
rv <- ret_vec[[fid]][est_dates]; mv <- mkt_vec[[fid]][est_dates]
ok <- !is.na(rv) & !is.na(mv)
rv <- rv[ok]; mv <- mv[ok]
if (length(rv) < 100) return(NULL)
m <- lm(rv ~ mv)
cf <- coef(m)
sig <- summary(m)$sigma # residual SE with (n-2) df
mrm <- mean(mv)
list(alpha = unname(cf[1]), beta = unname(cf[2]), sigma = sig,
n_est = length(rv), mean_rm = mrm, ss_rm = sum((mv - mrm)^2),
est_dates = est_dates[ok])
}
windows <- list(w3 = c(-1L, 1L), w2 = c(0L, 1L), w11 = c(-5L, 5L))
# Patell prediction-error-corrected SCAR over an event window.
# Var(CAR) = sigma^2 * sum_t [ 1 + 1/T + (Rm_t - mean_Rm)^2 / SS_Rm ]
window_scar <- function(m, eidx, w) {
offs <- seq.int(w[1], w[2])
ars <- numeric(0); pv <- numeric(0)
for (off in offs) {
tidx <- eidx + off
if (tidx < 0 || tidx >= n_dates) ret
…[truncated]Existing file was successfully overwritten at /app/analysis.R
cd /app && rm -rf outputs && mkdir -p outputs && Rscript analysis.R 2>&1
Done. n_valid_events = 35 rho_bar = 0.0057 hac_lag = 3 cal n_days = 230
cd /app && ls -la outputs/ && echo "=== JSON ===" && cat outputs/event_study_results.json
total 160
drwxr-sr-x 2 h2tagent h2tagent 4096 Jun 20 18:01 .
drwxrws--- 4 h2tagent h2tagent 4096 Jun 20 18:01 ..
-rw-r--r-- 1 h2tagent h2tagent 48876 Jun 20 18:01 car_timeline.png
-rw-r--r-- 1 h2tagent h2tagent 3619 Jun 20 18:01 event_cars.csv
-rw-r--r-- 1 h2tagent h2tagent 1839 Jun 20 18:01 event_study_results.json
-rw-r--r-- 1 h2tagent h2tagent 93652 Jun 20 18:01 portfolio_comparison.png
-rw-r--r-- 1 h2tagent h2tagent 6512 Jun 20 18:01 research_memo.md
=== 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.01163,
"patell_z": -5.984886,
"bmp_t": -4.992138,
"kp_t": -4.570158,
"pct_negative": 0.828571,
"n": 35
},
"window_2day": {
"mean_scar": -0.862243,
"patell_z": -5.101097,
"bmp_t": -4.509969,
"kp_t": -4.128747,
"pct_negative": 0.8,
"n": 35
},
"window_11day": {
"mean_scar": -0.450723,
"patell_z": -2.666514,
"bmp_t": -2.174875,
"kp_t": -1.991035,
"pct_negative": 0.628571,
"n": 35
}
},
"cross_section_hac": {
"intercept": 6.870415,
"log_units": -0.277206,
"media": -0.140035,
"severity": -0.049356,
"log_mcap": -0.349665,
"se_intercept": 1.989976,
"se_log_units": 0.143768,
"se_media": 0.045345,
"se_severity": 0.079685,
"se_log_mcap": 0.109201,
"r_squared": 0.365807,
"n_obs": 35,
"hac_lag": 3
},
"cross_section_wls": {
"intercept": 6.181414,
"log_units": -0.245301,
"media": -0.142987,
"severity": -0.068882,
"log_mcap": -0.301826,
"se_intercept": 2.373976,
"se_log_units": 0.119944,
"se_media": 0.063018,
"se_severity": 0.074244,
"se_log_mcap": 0.192047,
"r_squared": 0.307908,
"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.628867,
"wald_p": 1.1e-05,
"df": 3
}
}cd /app && Rscript -e '
suppressPackageStartupMessages(library(jsonlite))
ev <- read.csv("/app/outputs/event_cars.csv", stringsAsFactors=FALSE)
recalls <- read.csv("/app/data/recalls.csv"); firms <- read.csv("/app/data/firms.csv")
cs <- merge(ev[,c("event_id","firm_id","scar_3day")], 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),]
m <- lm(scar_3day ~ log_units + media_articles + severity_score + log_mcap, data=cs)
cat("OLS coefs (lm):\n"); print(round(coef(m),6))
cat("OLS R2 (lm):", round(summary(m)$r.squared,6), "\n")
cat("OLS SE (lm, homoskedastic):\n"); print(round(summary(m)$coefficients[,2],6))
w <- 1/cs$idio_vol^2
mw <- lm(scar_3day ~ log_units + media_articles + severity_score + log_mcap, data=cs, weights=w)
cat("\nWLS coefs (lm):\n"); print(round(coef(mw),6))
cat("WLS SE (lm):\n"); print(round(summary(mw)$coefficients[,2],6))
cat("WLS R2 (lm):", round(summary(mw)$r.squared,6), "\n")
'OLS coefs (lm):
(Intercept) log_units media_articles severity_score log_mcap
6.870415 -0.277206 -0.140035 -0.049356 -0.349665
OLS R2 (lm): 0.365807
OLS SE (lm, homoskedastic):
(Intercept) log_units media_articles severity_score log_mcap
2.191979 0.117060 0.059878 0.070713 0.168029
WLS coefs (lm):
(Intercept) log_units media_articles severity_score log_mcap
6.181414 -0.245301 -0.142987 -0.068882 -0.301826
WLS SE (lm):
(Intercept) log_units media_articles severity_score log_mcap
2.373976 0.119944 0.063018 0.074244 0.192047
WLS R2 (lm): 0.307908cd /app && Rscript -e '
ev <- read.csv("/app/outputs/event_cars.csv"); recalls <- read.csv("/app/data/recalls.csv"); firms <- read.csv("/app/data/firms.csv")
cs <- merge(ev[,c("event_id","firm_id","scar_3day")], 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),]
X <- cbind(1, cs$log_units, cs$media_articles, cs$severity_score, cs$log_mcap); y <- cs$scar_3day
N <- nrow(X); k <- ncol(X); bread <- solve(t(X)%*%X)
b <- bread %*% t(X) %*% y; u <- as.numeric(y - X%*%b)
E <- X * u # score matrix N x k
hac_meat <- function(L){
S <- t(E) %*% E # Gamma_0
if(L>=1) for(l in 1:L){ w <- 1 - l/(L+1); G <- t(E[(l+1):N,,drop=FALSE]) %*% E[1:(N-l),,drop=FALSE]; S <- S + w*(G + t(G)) }
S
}
# L=0 should equal White HC0
V0 <- bread %*% hac_meat(0) %*% bread
cat("HC0 (L=0) SE:\n"); print(round(sqrt(diag(V0)),6))
L <- floor(4*(N/100)^(2/9)); cat("Andrews L =", L, "\n")
V3 <- bread %*% hac_meat(L) %*% bread
cat("HAC (L=3) SE [independent score-based]:\n"); print(round(sqrt(diag(V3)),6))
' HC0 (L=0) SE: [1] 1.617519 0.113664 0.049337 0.062673 0.133896 Andrews L = 3 HAC (L=3) SE [independent score-based]: [1] 1.989976 0.143768 0.045345 0.079685 0.109201
cd /app && Rscript -e '
returns <- read.csv("/app/data/stock_returns.csv"); recalls <- read.csv("/app/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)
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"])
fdat <- returns[returns$firm_id==fid,]; rv<-setNames(fdat$return,as.character(fdat$date)); mv<-setNames(fdat$market_return,as.character(fdat$date))
est_end<-eidx-30-1; est_start<-est_end-200+1
ed<-as.character(all_dates[(est_start+1):(est_end+1)]); r<-rv[ed]; mk<-mv[ed]; ok<-!is.na(r)&!is.na(mk); r<-r[ok]; mk<-mk[ok]
m<-lm(r~mk); a<-coef(m)[1]; bb<-coef(m)[2]; sig<-summary(m)$sigma; T<-length(r); mrm<-mean(mk); ss<-sum((mk-mrm)^2)
cat(sprintf("alpha=%.6f beta=%.6f sigma=%.6f T=%d\n",a,bb,sig,T))
# 3-day window [-1,1]
car<-0; pv<-0; ar0<-NA
for(off in -1:1){ ds<-as.character(all_dates[eidx+off+1]); ar<-rv[ds]-a-bb*mv[ds]; car<-car+ar; pv<-pv+(1+1/T+(mv[ds]-mrm)^2/ss); if(off==0) ar0<-ar }
scar3<-car/sqrt(sig^2*pv)
cat(sprintf("hand CAR3=%.6f SCAR3=%.6f ar_day0=%.6f\n", car, scar3, ar0))
ev<-read.csv("/app/outputs/event_cars.csv"); print(ev[ev$event_id==1,c("scar_3day","ar_day0")])
'alpha=-0.002097 beta=0.789695 sigma=0.019936 T=200 hand CAR3=-0.096077 SCAR3=-2.773854 ar_day0=-0.018805 scar_3day ar_day0 1 -2.773854 -0.01880484
cd /app && Rscript -e '
returns <- read.csv("/app/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),]
fs <- sort(unique(returns$firm_id))
res <- list()
for(f in fs){ d<-returns[returns$firm_id==f,]; if(nrow(d)<30) next; mm<-lm(return~market_return,data=d); res[[f]]<-setNames(resid(mm),as.character(d$date)) }
rf<-names(res); cors<-c()
for(a in 1:(length(rf)-1)) for(b in (a+1):length(rf)){ ra<-res[[rf[a]]]; rb<-res[[rf[b]]]; cm<-intersect(names(ra),names(rb)); if(length(cm)<20) next; cors<-c(cors,cor(ra[cm],rb[cm])) }
cat("n pairs:",length(cors)," rho_bar =", round(mean(cors),6), "\n")
# aggregate check
ev<-read.csv("/app/outputs/event_cars.csv")
s<-ev$scar_3day; n<-length(s)
cat("3day: mean",round(mean(s),6)," patell",round(sum(s)/sqrt(n),6)," bmp",round(mean(s)/(sd(s)/sqrt(n)),6)," pctneg",round(mean(s<0),6),"\n")
rho<-mean(cors); cat("kp_t:", round(mean(s)/sqrt(var(s)*(1+(n-1)*rho)/n),6), "\n")
'n pairs: 153 rho_bar = 0.005682 3day: mean -1.01163 patell -5.984886 bmp -4.992138 pctneg 0.828571 kp_t: -4.570158
cd /app && Rscript -e '
returns <- read.csv("/app/data/stock_returns.csv"); recalls <- read.csv("/app/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)); nD<-length(all_dates); idx <- setNames(seq_along(all_dates)-1L, as.character(all_dates))
rv<-list(); for(f in unique(returns$firm_id)){ d<-returns[returns$firm_id==f,]; rv[[f]]<-setNames(d$return,as.character(d$date)) }
mkt<-tapply(returns$market_return,as.character(returns$date),function(x)x[1])
fei<-split(as.integer(idx[as.character(recalls$date)]), recalls$firm_id)
pd<-c(); pr<-c(); pm<-c()
for(d in 0:(nD-1)){ act<-c(); for(f in names(fei)){ e<-fei[[f]]; if(any(abs(d-e)<=30)) act<-c(act,f) }; if(!length(act)) next
ds<-as.character(all_dates[d+1]); rr<-sapply(act,function(f) rv[[f]][ds]); rr<-rr[!is.na(rr)]; if(!length(rr)) next
pd<-c(pd,ds); pr<-c(pr,mean(rr)); pm<-c(pm,as.numeric(mkt[ds])) }
o<-order(as.Date(pd)); pr<-pr[o]; pm<-pm[o]; pd<-pd[o]
cat("n_days:",length(pr)," date range:",pd[1],"to",pd[length(pd)],"\n")
m<-lm(pr~pm); s<-summary(m)
cat("alpha:",round(coef(m)[1],6)," beta:",round(coef(m)[2],6),"\n")
cat("t_alpha:",round(s$coefficients[1,3],6)," p:",round(s$coefficients[1,4],6),"\n")
'n_days: 230 date range: 2007-02-07 to 2007-12-25 alpha: -0.000858 beta: 1.033203 t_alpha: -1.34566 p: 0.179749
cd /app && Rscript -e '
returns <- read.csv("/app/data/stock_returns.csv"); recalls <- read.csv("/app/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)); nD<-length(all_dates); idx <- setNames(seq_along(all_dates)-1L, as.character(all_dates))
rv<-list(); mv<-list(); for(f in unique(returns$firm_id)){ d<-returns[returns$firm_id==f,]; rv[[f]]<-setNames(d$return,as.character(d$date)); mv[[f]]<-setNames(d$market_return,as.character(d$date)) }
ev<-read.csv("/app/outputs/event_cars.csv",stringsAsFactors=FALSE)
ev$eidx<-as.integer(idx[ev$date])
# Corrado
K<-c()
for(i in 1:nrow(ev)){ fid<-ev$firm_id[i]; e<-ev$eidx[i]; po<-c(); rr<-c()
for(off in -30:30){ t<-e+off; if(t<0||t>=nD) next; ds<-as.character(all_dates[t+1]); x<-rv[[fid]][ds]; if(is.na(x)) next; po<-c(po,off); rr<-c(rr,as.numeric(x)) }
n<-length(rr); rk<-rank(rr); mr<-(n+1)/2; sr<-sd(rk); dv<-c()
for(o in c(-1,0,1)){ p<-which(po==o); if(length(p)==1) dv<-c(dv,(rk[p]-mr)/sr) }
if(length(dv)) K<-c(K,mean(dv)) }
z<-mean(K)/(sd(K)/sqrt(length(K))); cat("Corrado z:",round(z,6)," p:",round(2*(1-pnorm(abs(z))),6)," N:",length(K),"\n")
# Cowan
ph<-c(); I<-c()
for(i in 1:nrow(ev)){ fid<-ev$firm_id[i]; e<-ev$eidx[i]; a<-NA; b<-NA
ee<-e-30-1; es<-ee-200+1; ed<-as.character(all_dates[(es+1):(ee+1)]); r<-rv[[fid]][ed]; mk<-mv[[fid]][ed]; ok<-!is.na(r)&!is.na(mk); r<-r[ok]; mk<-mk[ok]
m<-lm(r~mk); a<-coef(m)[1]; b<-coef(m)[2]
if(length(r)<50) next
are<-r-a-b*mk; ph<-c(ph,mean(are>0))
pa<-FALSE; for(off in c(-1,0,1)){ t<-e+off; ds<-as.character(all_dates[t+1]); x<-rv[[fid]][ds]; y<-mv[[fid]][ds]; if(is.na(x)||is.na(y)) next; if((x-a-b*y)>0) pa<-TRUE }
I<-c(I,as.numeric(pa)) }
pb<-mean(ph); fp<-mean(I); N<-length(I); zz<-(fp-pb)/sqrt(pb*(1-pb)/N)
cat("Cowan z:",round(zz,6)," p:",round(2*(1-pnorm(abs(zz))),6)," p_bar:",round(pb,6)," frac:",round(fp,6)," N:",N,"\n")
'Corrado z: -2.426518 p: 0.015244 N: 35 Cowan z: 0.253547 p: 0.799846 p_bar: 0.492859 frac: 0.514286 N: 35
cd /app && Rscript -e '
ev<-read.csv("/app/outputs/event_cars.csv")
M<-as.matrix(ev[,c("scar_3day","scar_2day","scar_11day")]); M<-M[complete.cases(M),,drop=FALSE]
N<-nrow(M); mb<-colMeans(M); S<-cov(M); W<-as.numeric(N*t(mb)%*%solve(S)%*%mb)
cat("Wald:",round(W,6)," p:",signif(1-pchisq(W,3),6)," N:",N,"\n")
' && echo "--- event_cars.csv (head & tail) ---" && head -4 outputs/event_cars.csv && echo "..." && tail -3 outputs/event_cars.csv && echo "rows:" && wc -l outputs/event_cars.csvWald: 25.62887 p: 1.14056e-05 N: 35 --- event_cars.csv (head & tail) --- "event_id","firm_id","date","scar_3day","scar_2day","scar_11day","ar_day0" 1,"FIRM_007","2007-03-21",-2.77385385944802,-2.03060185064421,-2.77014144097435,-0.0188048397516721 2,"FIRM_002","2007-03-28",1.66617104840486,2.2032063219835,1.43531764348162,0.0513410791394269 3,"FIRM_017","2007-04-16",0.94907492719969,1.03224371499574,1.49892343651693,0.00560955526504031 ... 33,"FIRM_013","2007-11-08",-0.526356372773951,-0.52373532134165,-0.308505132913324,-0.00467616980098902 34,"FIRM_017","2007-11-09",-2.56743883437834,-1.705510789566,-0.929888690726546,-0.026450830109875 35,"FIRM_011","2007-11-13",-2.71199846009415,-2.36135841115297,-1.190983990059,-0.0178536276477926 rows: 36 outputs/event_cars.csv
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: x = "Trading days relative to recall announcement (t = 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 (t = 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),
text = element_text(color = "gray15"),
axis.text = element_text(color = "gray25"))
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: color = "Series", linetype = "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: color = "Series", linetype = "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),
text = element_text(color = "gray15"),
axis.text = element_text(color = "gray25"))
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 -rf outputs && mkdir -p outputs && Rscript analysis.R 2>&1
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]
cd /app && echo "Memo word count:" && wc -w outputs/research_memo.md && echo "--- section headers ---" && grep '^#' outputs/research_memo.md && echo "--- JSON validity & integer types ---" && Rscript -e '
library(jsonlite); j<-fromJSON("/app/outputs/event_study_results.json")
cat("parse OK\n")
ints<-c(j$n_events,j$n_firms,j$n_firms_with_recalls,j$n_valid_events,j$aggregate_scars$window_3day$n,j$cross_section_hac$n_obs,j$cross_section_hac$hac_lag,j$cross_section_wls$n_obs,j$calendar_time$n_days,j$schipper_thompson$df)
cat("integer-valued fields:", paste(ints,collapse=","), "\n")
cat("all whole numbers:", all(ints==floor(ints)), "\n")
'Memo word count: 970 outputs/research_memo.md --- section headers --- # Research Memo: Stock-Market Impact of Product-Recall Announcements in the Toy Industry ## Executive summary ## 1. Magnitude and significance of the announcement effect ## 2. What drives the cross-section of abnormal returns ## 3. Calendar-time portfolio versus short-window results ## 4. Do the non-parametric tests agree? ## 5. Practical conclusion for regulators and investors --- JSON validity & integer types --- parse OK integer-valued fields: 35,18,14,35,35,35,3,35,230,3 all whole numbers: TRUE
cd /app && Rscript -e '
returns <- read.csv("/app/data/stock_returns.csv"); recalls <- read.csv("/app/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))
sc1<-c(); sc2<-c(); sc3<-c()
for(i in 1:nrow(recalls)){ fid<-recalls$firm_id[i]; eidx<-as.integer(idx[as.character(recalls$date[i])])
fdat<-returns[returns$firm_id==fid,]; rv<-setNames(fdat$return,as.character(fdat$date)); mv<-setNames(fdat$market_return,as.character(fdat$date))
ee<-eidx-31; es<-ee-199; ed<-as.character(all_dates[(es+1):(ee+1)]); r<-rv[ed]; mk<-mv[ed]; ok<-!is.na(r)&!is.na(mk); r<-r[ok]; mk<-mk[ok]
m<-lm(r~mk); a<-coef(m)[1]; b<-coef(m)[2]; sig<-summary(m)$sigma; T<-length(r); mrm<-mean(mk); ss<-sum((mk-mrm)^2)
ars<-c(); pv<-c(); devs<-c()
for(off in -1:1){ ds<-as.character(all_dates[eidx+off+1]); ar<-as.numeric(rv[ds]-a-b*mv[ds]); ars<-c(ars,ar); dev<-as.numeric(mv[ds])-mrm; pv<-c(pv,1+1/T+dev^2/ss); devs<-c(devs,dev) }
car<-sum(ars); L<-3
sc1<-c(sc1, car/sqrt(sig^2*sum(pv))) # (i) sum of daily pred var
sc2<-c(sc2, car/sqrt(sig^2*(L + L^2/T + (sum(devs))^2/ss))) # (ii) full CLM cross-day cov
sc3<-c(sc3, sum(ars/(sig*sqrt(pv)))/sqrt(L)) # (iii) sum SAR / sqrt(L)
}
cat("mean SCAR (i) diag :", round(mean(sc1),6), " patellZ:", round(sum(sc1)/sqrt(length(sc1)),4),"\n")
cat("mean SCAR (ii) CLM :", round(mean(sc2),6), " patellZ:", round(sum(sc2)/sqrt(length(sc2)),4),"\n")
cat("mean SCAR (iii) SAR:", round(mean(sc3),6), " patellZ:", round(sum(sc3)/sqrt(length(sc3)),4),"\n")
cat("corr(i,iii):", round(cor(sc1,sc3),6), " max|i-iii|:", round(max(abs(sc1-sc3)),6), "\n")
cat("max|i-ii|:", round(max(abs(sc1-sc2)),6), "\n")
'mean SCAR (i) diag : -1.01163 patellZ: -5.9849 mean SCAR (ii) CLM : -1.007522 patellZ: -5.9606 mean SCAR (iii) SAR: -1.011846 patellZ: -5.9862 corr(i,iii): 0.999998 max|i-iii|: 0.009714 max|i-ii|: 0.025083
cd /app && Rscript -e '
returns <- read.csv("/app/data/stock_returns.csv"); recalls <- read.csv("/app/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))
f <- function(gapoff){ sc<-c(); for(i in 1:nrow(recalls)){ fid<-recalls$firm_id[i]; eidx<-as.integer(idx[as.character(recalls$date[i])])
fdat<-returns[returns$firm_id==fid,]; rv<-setNames(fdat$return,as.character(fdat$date)); mv<-setNames(fdat$market_return,as.character(fdat$date))
ee<-eidx-gapoff; es<-ee-199; if(es<0) next; ed<-as.character(all_dates[(es+1):(ee+1)]); r<-rv[ed]; mk<-mv[ed]; ok<-!is.na(r)&!is.na(mk); r<-r[ok]; mk<-mk[ok]
m<-lm(r~mk); a<-coef(m)[1]; b<-coef(m)[2]; sig<-summary(m)$sigma; T<-length(r); mrm<-mean(mk); ss<-sum((mk-mrm)^2)
ars<-c(); pv<-c(); for(off in -1:1){ ds<-as.character(all_dates[eidx+off+1]); ars<-c(ars,as.numeric(rv[ds]-a-b*mv[ds])); pv<-c(pv,1+1/T+(as.numeric(mv[ds])-mrm)^2/ss) }
sc<-c(sc, sum(ars)/sqrt(sig^2*sum(pv))) }; sc }
b <- f(31); a <- f(30)
cat("(B) est_end=eidx-31: mean SCAR", round(mean(b),6)," PatellZ", round(sum(b)/sqrt(length(b)),4),"\n")
cat("(A) est_end=eidx-30: mean SCAR", round(mean(a),6)," PatellZ", round(sum(a)/sqrt(length(a)),4),"\n")
cat("max abs diff per-event:", round(max(abs(a-b)),6), "\n")
'(B) est_end=eidx-31: mean SCAR -1.01163 PatellZ -5.9849 (A) est_end=eidx-30: mean SCAR -1.008156 PatellZ -5.9643 max abs diff per-event: 0.046258
cd /app && Rscript -e '
library(jsonlite); j<-fromJSON("/app/outputs/event_study_results.json"); h<-j$cross_section_hac
for(v in c("log_units","media","severity","log_mcap")){ t<-h[[v]]/h[[paste0("se_",v)]]; cat(sprintf("%-10s coef=% .4f HACse=%.4f t=% .2f\n", v, h[[v]], h[[paste0("se_",v)]], t)) }
'log_units coef=-0.2772 HACse=0.1438 t=-1.93 media coef=-0.1400 HACse=0.0453 t=-3.09 severity coef=-0.0494 HACse=0.0797 t=-0.62 log_mcap coef=-0.3497 HACse=0.1092 t=-3.20
command: str_replace
path: /app/analysis.R
old_str: car3 <- mean(event_df$car_3day, na.rm = TRUE)
p_patell_3 <- 2 * (1 - pnorm(abs(agg_3$patell_z)))
p_bmp_3 <- 2 * pt(-abs(agg_3$bmp_t), df = agg_3$n - 1)
new_str: car3 <- mean(event_df$car_3day, na.rm = TRUE)
p_patell_3 <- 2 * (1 - pnorm(abs(agg_3$patell_z)))
p_bmp_3 <- 2 * pt(-abs(agg_3$bmp_t), df = agg_3$n - 1)
# HAC t-statistics for the cross-sectional drivers (for the memo narrative)
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_tag <- function(t) { at <- abs(t)
if (at >= 2.576) "statistically significant at the 1% level" else
if (at >= 1.960) "statistically significant at the 5% level" else
if (at >= 1.645) "marginally significant (10% level)" else "not statistically significant" }
dir_tag <- function(b) if (b < 0) "amplifies the share-price loss (a more negative SCAR)" else
"attenuates the loss (a less negative SCAR)"The file /app/analysis.R has been edited successfully.
command: str_replace
path: /app/analysis.R
old_str: "with an R-squared of ", sprintf("%.3f", cs_hac$r_squared), ". The weighted least squares specification, ",
"which down-weights high-idiosyncratic-volatility firms, tells a consistent story (severity coefficient ",
sprintf("%.4f", cs_wls$severity), ", SE ", sprintf("%.4f", cs_wls$se_severity), "). ",
"The economic intuition is straightforward. More severe hazards (for example lead paint or burn risks) and ",
"larger-scale recalls threaten bigger direct cash outflows and larger legal and reputational tails, so the ",
"sign and relative magnitude of the severity and scale coefficients speak directly to how investors price ",
"recall risk. Media coverage proxies for the salience and breadth of the news and can intensify consumer and ",
"regulatory responses. Firm size typically cushions the blow: larger, more diversified manufacturers can ",
"absorb a single product's recall with a smaller proportional hit to enterprise value, so a negative relation ",
"between size and the loss (equivalently a less negative SCAR for big firms) is the expected pattern.\n\n",
new_str: "with an R-squared of ", sprintf("%.3f", cs_hac$r_squared), ". In HAC t-statistic terms these are: ",
"log(units) t = ", sprintf("%.2f", t_units), " (", sig_tag(t_units), "), media t = ", sprintf("%.2f", t_media),
" (", sig_tag(t_media), "), severity t = ", sprintf("%.2f", t_sev), " (", sig_tag(t_sev), "), and ",
"log(market cap) t = ", sprintf("%.2f", t_mcap), " (", sig_tag(t_mcap), "). The weighted least squares ",
"specification, which down-weights high-idiosyncratic-volatility firms, tells a consistent story (severity ",
"coefficient ", sprintf("%.4f", cs_wls$severity), ", SE ", sprintf("%.4f", cs_wls$se_severity), "). ",
"The economic reading is as follows. Recall scale ", dir_tag(cs_hac$log_units), ": larger-unit recalls imply ",
"bigger direct remediation cash outflows and wider consumer exposure, so the market marks the firm down more. ",
"Media coverage ", dir_tag(cs_hac$media), " and is one of the sharpest drivers here, which fits the idea that ",
"salience and breadth of news amplify consumer, retailer, and regulatory responses beyond the mechanical cost ",
"of the recall itself. The hazard-severity score ", dir_tag(cs_hac$severity), " but is ", sig_tag(t_sev),
", plausibly because severity is already correlated with units and media coverage, so its marginal ",
"contribution is hard to identify separately in a sample of this size. Firm size is the most striking result: ",
"the log-market-cap coefficient ", dir_tag(cs_hac$log_mcap), " and is ", sig_tag(t_mcap), ". Naively one ",
"expects large, diversified manufacturers to be cushioned, but the dependent variable is a *standardized* CAR. ",
"Larger firms have lower idiosyncratic volatility, so an economically similar percentage loss is scaled by a ",
"smaller denominator and registers as a larger number of standard deviations. Part of the size effect may also ",
"reflect that recalls by prominent firms attract disproportionate scrutiny. This underscores that ",
"cross-sectional SCAR coefficients blend genuine economic exposure with the volatility normalization.\n\n",The file /app/analysis.R has been edited successfully.
cd /app && rm -rf outputs && mkdir -p outputs && Rscript analysis.R 2>&1 && echo "=== word count ===" && wc -w outputs/research_memo.md
Done. n_valid_events = 35 rho_bar = 0.0057 hac_lag = 3 cal n_days = 230 === word count === 1121 outputs/research_memo.md
cd /app && sed -n '/## 2\./,/## 3\./p' outputs/research_memo.md
## 2. What drives the cross-section of abnormal returns Regressing the three-day SCAR on recall scale (log units recalled), media coverage (article count), hazard severity, and firm size (log market capitalization) isolates the characteristics that amplify or dampen the reaction. Using HAC (Newey-West, lag 3) standard errors, the estimated slopes are: log(units) = -0.2772 (SE 0.1438), media articles = -0.1400 (SE 0.0453), severity = -0.0494 (SE 0.0797), and log(market cap) = -0.3497 (SE 0.1092), with an R-squared of 0.366. In HAC t-statistic terms these are: log(units) t = -1.93 (marginally significant (10% level)), media t = -3.09 (statistically significant at the 1% level), severity t = -0.62 (not statistically significant), and log(market cap) t = -3.20 (statistically significant at the 1% level). The weighted least squares specification, which down-weights high-idiosyncratic-volatility firms, tells a consistent story (severity coefficient -0.0689, SE 0.0742). The economic reading is as follows. Recall scale amplifies the share-price loss (a more negative SCAR): larger-unit recalls imply bigger direct remediation cash outflows and wider consumer exposure, so the market marks the firm down more. Media coverage amplifies the share-price loss (a more negative SCAR) and is one of the sharpest drivers here, which fits the idea that salience and breadth of news amplify consumer, retailer, and regulatory responses beyond the mechanical cost of the recall itself. The hazard-severity score amplifies the share-price loss (a more negative SCAR) but is not statistically significant, plausibly because severity is already correlated with units and media coverage, so its marginal contribution is hard to identify separately in a sample of this size. Firm size is the most striking result: the log-market-cap coefficient amplifies the share-price loss (a more negative SCAR) and is statistically significant at the 1% level. Naively one expects large, diversified manufacturers to be cushioned, but the dependent variable is a *standardized* CAR. Larger firms have lower idiosyncratic volatility, so an economically similar percentage loss is scaled by a smaller denominator and registers as a larger number of standard deviations. Part of the size effect may also reflect that recalls by prominent firms attract disproportionate scrutiny. This underscores that cross-sectional SCAR coefficients blend genuine economic exposure with the volatility normalization. ## 3. Calendar-time portfolio versus short-window results
cd /app && Rscript -e '
f<-read.csv("/app/data/firms.csv")
cat("cor(log(mcap), idio_vol):", round(cor(log(f$market_cap_mm), f$idio_vol),3), "\n")
cat("cor(log(mcap), beta):", round(cor(log(f$market_cap_mm), f$beta),3), "\n")
'cor(log(mcap), idio_vol): -0.32 cor(log(mcap), beta): -0.118
command: str_replace
path: /app/analysis.R
old_str: "), with an average positive-AR probability p-bar of ", sprintf("%.3f", p_bar), " against a realized ",
"positive-window fraction of ", sprintf("%.3f", frac_positive), ". ",
if (corr_p < 0.1 || cowan_p < 0.1)
"Because the rank and/or sign evidence points in the same direction as the parametric tests, we can be confident that the measured reaction is not an artifact of a few outlier observations or of non-normality; it reflects a genuine shift in the central tendency and the sign of abnormal returns."
else
"Here the non-parametric tests are more muted than the parametric ones, a pattern that typically signals that the parametric averages are influenced by a subset of large-magnitude outliers rather than a uniform shift across all events; the distribution of abnormal returns is skewed and fat-tailed rather than cleanly normal.",
"\n\n",
new_str: "), with an average positive-AR probability p-bar of ", sprintf("%.3f", p_bar), " against a realized ",
"positive-window fraction of ", sprintf("%.3f", frac_positive), ". ",
"The Corrado rank test is ", sig_word(corr_p), " and carries the same negative sign as the parametric ",
"statistics, which is the important corroboration: because the rank test makes no normality assumption and is ",
"robust to the fat tails of daily returns, its agreement tells us the measured drop is a genuine shift in the ",
"location of the return distribution and not an artifact of a few outliers. The Cowan generalized sign test, ",
"by contrast, is ", sig_word(cowan_p), ". This apparent disagreement is largely mechanical rather than ",
"substantive: as specified, the Cowan indicator equals one whenever *any* of the three days in [-1,+1] has a ",
"positive abnormal return, an event with a high baseline probability (roughly 1 - (1 - p-bar)^3 ~ 0.87 when ",
"p-bar is near one-half) even for firms whose net three-day reaction is decidedly negative. The test therefore ",
"has low power against the kind of concentrated, net-negative move we observe, so its silence does not overturn ",
"the rank and parametric evidence. Taken together, the non-parametric battery supports the conclusion that ",
"abnormal returns are left-shifted around recalls, while reminding us that the return distribution is skewed ",
"and heavy-tailed, so conclusions that lean on a single test statistic should be treated with caution.\n\n",The file /app/analysis.R has been edited successfully.
cd /app && rm -rf outputs && mkdir -p outputs && Rscript analysis.R 2>&1 && echo "=== wc ===" && wc -w outputs/research_memo.md && echo "=== section 4 ===" && sed -n '/## 4\./,/## 5\./p' outputs/research_memo.md
Done. n_valid_events = 35 rho_bar = 0.0057 hac_lag = 3 cal n_days = 230 === wc === 1276 outputs/research_memo.md === section 4 === ## 4. Do the non-parametric tests agree? Parametric tests assume approximately normal abnormal returns, an assumption that fat-tailed daily stock returns often violate. We therefore cross-check with two distribution-free tests. The Corrado (1989) rank test yields z = -2.43 (p = 0.0152), and the Cowan (1992) generalized sign test yields z = 0.25 (p = 0.7998), with an average positive-AR probability p-bar of 0.493 against a realized positive-window fraction of 0.514. The Corrado rank test is statistically significant at the 5% level and carries the same negative sign as the parametric statistics, which is the important corroboration: because the rank test makes no normality assumption and is robust to the fat tails of daily returns, its agreement tells us the measured drop is a genuine shift in the location of the return distribution and not an artifact of a few outliers. The Cowan generalized sign test, by contrast, is statistically insignificant. This apparent disagreement is largely mechanical rather than substantive: as specified, the Cowan indicator equals one whenever *any* of the three days in [-1,+1] has a positive abnormal return, an event with a high baseline probability (roughly 1 - (1 - p-bar)^3 ~ 0.87 when p-bar is near one-half) even for firms whose net three-day reaction is decidedly negative. The test therefore has low power against the kind of concentrated, net-negative move we observe, so its silence does not overturn the rank and parametric evidence. Taken together, the non-parametric battery supports the conclusion that abnormal returns are left-shifted around recalls, while reminding us that the return distribution is skewed and heavy-tailed, so conclusions that lean on a single test statistic should be treated with caution. ## 5. Practical conclusion for regulators and investors
command: str_replace
path: /app/analysis.R
old_str: "The Cowan generalized sign test, ",
"by contrast, is ", sig_word(cowan_p), ". This apparent disagreement is largely mechanical rather than ",
"substantive: as specified, the Cowan indicator equals one whenever *any* of the three days in [-1,+1] has a ",
"positive abnormal return, an event with a high baseline probability (roughly 1 - (1 - p-bar)^3 ~ 0.87 when ",
"p-bar is near one-half) even for firms whose net three-day reaction is decidedly negative. The test therefore ",
"has low power against the kind of concentrated, net-negative move we observe, so its silence does not overturn ",
"the rank and parametric evidence. Taken together, the non-parametric battery supports the conclusion that ",
new_str: "The Cowan generalized sign test, ",
"by contrast, is ", sig_word(cowan_p), ". This apparent disagreement is a benchmarking artifact rather than ",
"contradictory evidence. As specified, the test compares the fraction of events with at least one positive ",
"abnormal return somewhere in the three-day window (frac_positive = ", sprintf("%.3f", frac_positive),
") against p-bar = ", sprintf("%.3f", p_bar), ", the average single-day probability of a positive abnormal ",
"return. If abnormal returns were truly neutral, the probability that at least one of three days is positive ",
"would be far higher - on the order of 1 - (1 - p-bar)^3 ~ 0.87 - so the realized value of just ",
sprintf("%.3f", frac_positive), " actually reveals that in roughly half of the events not a single day in the ",
"window delivered a positive abnormal return, which is itself a strong symptom of pervasive negativity. ",
"Because the reported statistic instead measures frac_positive against the one-day rate p-bar, the two nearly ",
"cancel and the z-score is small; the insignificance reflects the test's construction and low power here, not ",
"an absence of an effect. Taken together, the non-parametric battery supports the conclusion that ",[stderr] No replacement was performed, old_str `"The Cowan generalized sign test, ", "by contrast, is ", sig_word(cowan_p), ". This apparent disagreement is largely mechanical rather than ", "substantive: as specified, the Cowan indicator equals one whenever *any* of the three days in [-1,+1] has a ", "positive abnormal return, an event with a high baseline probability (roughly 1 - (1 - p-bar)^3 ~ 0.87 when ", "p-bar is near one-half) even for firms whose net three-day reaction is decidedly negative. The test therefore ", "has low power against the kind of concentrated, net-negative move we observe, so its silence does not overturn ", "the rank and parametric evidence. Taken together, the non-parametric battery supports the conclusion that ",` did not appear verbatim in /app/analysis.R.
cd /app && grep -n "mechanical rather than\|high baseline\|Cowan generalized sign test, by\|0.87\|net three-day reaction" analysis.R
631:"by contrast, is ", sig_word(cowan_p), ". This apparent disagreement is largely mechanical rather than ", 633:"positive abnormal return, an event with a high baseline probability (roughly 1 - (1 - p-bar)^3 ~ 0.87 when ", 634:"p-bar is near one-half) even for firms whose net three-day reaction is decidedly negative. The test therefore ",
cd /app && sed -n '628,640p' analysis.R
"statistics, which is the important corroboration: because the rank test makes no normality assumption and is ", "robust to the fat tails of daily returns, its agreement tells us the measured drop is a genuine shift in the ", "location of the return distribution and not an artifact of a few outliers. The Cowan generalized sign test, ", "by contrast, is ", sig_word(cowan_p), ". This apparent disagreement is largely mechanical rather than ", "substantive: as specified, the Cowan indicator equals one whenever *any* of the three days in [-1,+1] has a ", "positive abnormal return, an event with a high baseline probability (roughly 1 - (1 - p-bar)^3 ~ 0.87 when ", "p-bar is near one-half) even for firms whose net three-day reaction is decidedly negative. The test therefore ", "has low power against the kind of concentrated, net-negative move we observe, so its silence does not overturn ", "the rank and parametric evidence. Taken together, the non-parametric battery supports the conclusion that ", "abnormal returns are left-shifted around recalls, while reminding us that the return distribution is skewed ", "and heavy-tailed, so conclusions that lean on a single test statistic should be treated with caution.\n\n", "## 5. Practical conclusion for regulators and investors\n\n",
cd /app && python3 - <<'PY'
with open('analysis.R') as f:
lines = f.readlines()
# Replace lines 631-635 (1-based) -> indices 630:635
new_block = [
'"by contrast, is ", sig_word(cowan_p), ". This apparent disagreement is a benchmarking artifact rather than ",\n',
'"contradictory evidence. As specified, the test compares the fraction of events with at least one positive ",\n',
'"abnormal return somewhere in the three-day window (frac_positive = ", sprintf("%.3f", frac_positive),\n',
'") against p-bar = ", sprintf("%.3f", p_bar), ", the average single-day probability of a positive abnormal ",\n',
'"return. If abnormal returns were neutral, the chance that at least one of three days is positive would be ",\n',
'"far higher, on the order of 1 minus (1 minus p-bar) cubed (about 0.87), so the realized value of only ",\n',
'sprintf("%.3f", frac_positive), " reveals that in roughly half of the events not a single day in the window ",\n',
'"produced a positive abnormal return, which is itself a strong symptom of pervasive negativity. Because the ",\n',
'"reported statistic instead measures frac_positive against the one-day rate p-bar, the two nearly cancel and ",\n',
'"the z-score is small: the insignificance reflects the test construction and its low power here, not an ",\n',
'"absence of an effect. Taken together, the non-parametric battery supports the conclusion that ",\n',
]
assert 'by contrast, is ' in lines[630], lines[630]
assert 'does not overturn' in lines[634], lines[634]
lines[630:635] = new_block
with open('analysis.R','w') as f:
f.writelines(lines)
print("done; total lines now", len(lines))
PYdone; total lines now 661
cd /app && rm -rf outputs && mkdir -p outputs && Rscript analysis.R 2>&1 && echo "=== wc ===" && wc -w outputs/research_memo.md && echo && sed -n '/## 4\./,/## 5\./p' outputs/research_memo.md | tail -12
Done. n_valid_events = 35 rho_bar = 0.0057 hac_lag = 3 cal n_days = 230 === wc === 1359 outputs/research_memo.md ## 4. Do the non-parametric tests agree? Parametric tests assume approximately normal abnormal returns, an assumption that fat-tailed daily stock returns often violate. We therefore cross-check with two distribution-free tests. The Corrado (1989) rank test yields z = -2.43 (p = 0.0152), and the Cowan (1992) generalized sign test yields z = 0.25 (p = 0.7998), with an average positive-AR probability p-bar of 0.493 against a realized positive-window fraction of 0.514. The Corrado rank test is statistically significant at the 5% level and carries the same negative sign as the parametric statistics, which is the important corroboration: because the rank test makes no normality assumption and is robust to the fat tails of daily returns, its agreement tells us the measured drop is a genuine shift in the location of the return distribution and not an artifact of a few outliers. The Cowan generalized sign test, by contrast, is statistically insignificant. This apparent disagreement is a benchmarking artifact rather than contradictory evidence. As specified, the test compares the fraction of events with at least one positive abnormal return somewhere in the three-day window (frac_positive = 0.514) against p-bar = 0.493, the average single-day probability of a positive abnormal return. If abnormal returns were neutral, the chance that at least one of three days is positive would be far higher, on the order of 1 minus (1 minus p-bar) cubed (about 0.87), so the realized value of only 0.514 reveals that in roughly half of the events not a single day in the window produced a positive abnormal return, which is itself a strong symptom of pervasive negativity. Because the reported statistic instead measures frac_positive against the one-day rate p-bar, the two nearly cancel and the z-score is small: the insignificance reflects the test construction and its low power here, not an absence of an effect. Taken together, the non-parametric battery supports the conclusion that the rank and parametric evidence. Taken together, the non-parametric battery supports the conclusion that abnormal returns are left-shifted around recalls, while reminding us that the return distribution is skewed and heavy-tailed, so conclusions that lean on a single test statistic should be treated with caution. ## 5. Practical conclusion for regulators and investors
cd /app && grep -n "the rank and parametric evidence. Taken together" analysis.R
642:"the rank and parametric evidence. Taken together, the non-parametric battery supports the conclusion that ",
cd /app && sed -n '640,644p' analysis.R
"the z-score is small: the insignificance reflects the test construction and its low power here, not an ", "absence of an effect. Taken together, the non-parametric battery supports the conclusion that ", "the rank and parametric evidence. Taken together, the non-parametric battery supports the conclusion that ", "abnormal returns are left-shifted around recalls, while reminding us that the return distribution is skewed ", "and heavy-tailed, so conclusions that lean on a single test statistic should be treated with caution.\n\n",
cd /app && sed -i '642d' analysis.R && sed -n '640,644p' analysis.R
"the z-score is small: the insignificance reflects the test construction and its low power here, not an ", "absence of an effect. Taken together, the non-parametric battery supports the conclusion that ", "abnormal returns are left-shifted around recalls, while reminding us that the return distribution is skewed ", "and heavy-tailed, so conclusions that lean on a single test statistic should be treated with caution.\n\n",
cd /app && rm -rf outputs && mkdir -p outputs && Rscript analysis.R 2>&1 && echo "=== wc ===" && wc -w outputs/research_memo.md && echo && sed -n '/## 4\./,/## 5\./p' outputs/research_memo.md | tail -6
Done. n_valid_events = 35 rho_bar = 0.0057 hac_lag = 3 cal n_days = 230 === wc === 1345 outputs/research_memo.md ## 4. Do the non-parametric tests agree? Parametric tests assume approximately normal abnormal returns, an assumption that fat-tailed daily stock returns often violate. We therefore cross-check with two distribution-free tests. The Corrado (1989) rank test yields z = -2.43 (p = 0.0152), and the Cowan (1992) generalized sign test yields z = 0.25 (p = 0.7998), with an average positive-AR probability p-bar of 0.493 against a realized positive-window fraction of 0.514. The Corrado rank test is statistically significant at the 5% level and carries the same negative sign as the parametric statistics, which is the important corroboration: because the rank test makes no normality assumption and is robust to the fat tails of daily returns, its agreement tells us the measured drop is a genuine shift in the location of the return distribution and not an artifact of a few outliers. The Cowan generalized sign test, by contrast, is statistically insignificant. This apparent disagreement is a benchmarking artifact rather than contradictory evidence. As specified, the test compares the fraction of events with at least one positive abnormal return somewhere in the three-day window (frac_positive = 0.514) against p-bar = 0.493, the average single-day probability of a positive abnormal return. If abnormal returns were neutral, the chance that at least one of three days is positive would be far higher, on the order of 1 minus (1 minus p-bar) cubed (about 0.87), so the realized value of only 0.514 reveals that in roughly half of the events not a single day in the window produced a positive abnormal return, which is itself a strong symptom of pervasive negativity. Because the reported statistic instead measures frac_positive against the one-day rate p-bar, the two nearly cancel and the z-score is small: the insignificance reflects the test construction and its low power here, not an absence of an effect. Taken together, the non-parametric battery supports the conclusion that abnormal returns are left-shifted around recalls, while reminding us that the return distribution is skewed and heavy-tailed, so conclusions that lean on a single test statistic should be treated with caution. ## 5. Practical conclusion for regulators and investors
cd /app && ls -la outputs/ && echo "=== JSON re-validate ===" && Rscript -e 'library(jsonlite); j<-fromJSON("/app/outputs/event_study_results.json"); cat("keys:", paste(names(j),collapse=", "), "\n"); cat("n_valid_events:", j$n_valid_events, " rho_bar:", j$rho_bar, "\n"); cat("3day patell/bmp/kp:", j$aggregate_scars$window_3day$patell_z, j$aggregate_scars$window_3day$bmp_t, j$aggregate_scars$window_3day$kp_t, "\n"); cat("calendar alpha/p:", j$calendar_time$alpha, j$calendar_time$p_value, "\n"); cat("schipper wald/p/df:", j$schipper_thompson$wald_stat, j$schipper_thompson$wald_p, j$schipper_thompson$df, "\n")'total 164 drwxr-sr-x 2 h2tagent h2tagent 4096 Jun 20 18:07 . drwxrws--- 4 h2tagent h2tagent 4096 Jun 20 18:07 .. -rw-r--r-- 1 h2tagent h2tagent 53030 Jun 20 18:07 car_timeline.png -rw-r--r-- 1 h2tagent h2tagent 3619 Jun 20 18:07 event_cars.csv -rw-r--r-- 1 h2tagent h2tagent 1839 Jun 20 18:07 event_study_results.json -rw-r--r-- 1 h2tagent h2tagent 90945 Jun 20 18:07 portfolio_comparison.png -rw-r--r-- 1 h2tagent h2tagent 8990 Jun 20 18:07 research_memo.md === JSON re-validate === keys: 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 n_valid_events: 35 rho_bar: 0.005682 3day patell/bmp/kp: -5.984886 -4.992138 -4.570158 calendar alpha/p: -0.000858 0.179749 schipper wald/p/df: 25.62887 1.1e-05 3
cd /app && cat outputs/research_memo.md
# Research Memo: Stock-Market Impact of Product-Recall Announcements in the Toy Industry ## Executive summary We conduct a modern event study of 35 product-recall announcements issued by 14 toy manufacturers (out of 18 firms in the sample). Using a market-model benchmark estimated over a 200-trading-day window that ends 30 days before each announcement, we measure the abnormal stock-price reaction in three event windows and subject it to a battery of parametric and non-parametric tests. The central finding is that recall announcements are associated with an average three-day standardized cumulative abnormal return (SCAR) of -1.012 and an average raw three-day cumulative abnormal return (CAR) of -2.92%. This reaction is highly statistically significant under the Patell test (Z = -5.98), and the conclusion is corroborated by the BMP (t = -4.99) and Kolari-Pynnonen (t = -4.57) statistics that correct, respectively, for event-induced variance and for cross-sectional correlation (mean pairwise residual correlation rho-bar = 0.0057). ## 1. Magnitude and significance of the announcement effect Across the 35 events with a usable three-day window, 82.86% of standardized CARs are negative. The two-day [0,+1] window shows a mean SCAR of -0.862 (Patell Z = -5.10), while the wider eleven-day [-5,+5] window averages -0.451 (Patell Z = -2.67). The fact that the tighter windows carry a comparable or sharper signal than the eleven-day window indicates that the information is impounded quickly and around the announcement date rather than drifting in over many sessions. The joint Schipper-Thompson Wald test, which asks whether the three window means are simultaneously zero, returns a statistic of 25.63 on 3 degrees of freedom (p = 0.0000), decisively rejecting the null of no reaction. Economically, a move of this size on a single announcement is material: it represents a rapid revaluation of the firm driven by expected recall costs, litigation and remediation expense, and reputational damage to the brand. ## 2. What drives the cross-section of abnormal returns Regressing the three-day SCAR on recall scale (log units recalled), media coverage (article count), hazard severity, and firm size (log market capitalization) isolates the characteristics that amplify or dampen the reaction. Using HAC (Newey-West, lag 3) standard errors, the estimated slopes are: log(units) = -0.2772 (SE 0.1438), media articles = -0.1400 (SE 0.0453), severity = -0.0494 (SE 0.0797), and log(market cap) = -0.3497 (SE 0.1092), with an R-squared of 0.366. In HAC t-statistic terms these are: log(units) t = -1.93 (marginally significant (10% level)), media t = -3.09 (statistically significant at the 1% level), severity t = -0.62 (not statistically significant), and log(market cap) t = -3.20 (statistically significant at the 1% level). The weighted least squares specification, which down-weights high-idiosyncratic-volatility firms, tells a consistent story (severity coefficient -0.0689, SE 0.0742). The economic reading is as follows. Recall scale amplifies the share-price loss (a more negative SCAR): larger-unit recalls imply bigger direct remediation cash outflows and wider consumer exposure, so the market marks the firm down more. Media coverage amplifies the share-price loss (a more negative SCAR) and is one of the sharpest drivers here, which fits the idea that salience and breadth of news amplify consumer, retailer, and regulatory responses beyond the mechanical cost of the recall itself. The hazard-severity score amplifies the share-price loss (a more negative SCAR) but is not statistically significant, plausibly because severity is already correlated with units and media coverage, so its marginal contribution is hard to identify separately in a sample of this size. Firm size is the most striking result: the log-market-cap coefficient amplifies the share-price loss (a more negative SCAR) and is statistically significant at the 1% level. Naively one expects large, dive …[truncated]
command: str_replace
path: /app/analysis.R
old_str: pct <- function(x) sprintf("%.2f%%", 100 * x)
new_str: pct <- function(x) sprintf("%.2f%%", 100 * x)
fmt_p <- function(p) if (p < 0.0001) "< 0.0001" else sprintf("%.4f", p)The file /app/analysis.R has been edited successfully.
command: str_replace
path: /app/analysis.R
old_str: "zero, returns a statistic of ", sprintf("%.2f", wald_stat), " on 3 degrees of freedom (p = ",
sprintf("%.4f", wald_p), "), ", if (wald_p < 0.05) "decisively rejecting" else "failing to reject",
new_str: "zero, returns a statistic of ", sprintf("%.2f", wald_stat), " on 3 degrees of freedom (p = ",
fmt_p(wald_p), "), ", if (wald_p < 0.05) "decisively rejecting" else "failing to reject",The file /app/analysis.R has been edited successfully.
command: str_replace path: /app/analysis.R old_str: "Second, severity, scale, and media salience are useful conditioning variables for sizing the likely hit, ", "while larger firms tend to be more resilient. In short, product recalls in the toy industry are a clear, ", new_str: "Second, severity, scale, and media salience are useful conditioning variables for sizing the likely hit. ", "Firm size must be read carefully: in raw percentage terms larger, more diversified manufacturers tend to ", "absorb a single recall more easily, yet because they are also less volatile their *risk-adjusted* (standardized) ", "reaction can actually look larger, so size is not a simple proxy for resilience. In short, product recalls in ", "the toy industry are a clear, ",
The file /app/analysis.R has been edited successfully.
cd /app && rm -rf outputs && mkdir -p outputs && Rscript analysis.R 2>&1 && echo "=== wc ===" && wc -w outputs/research_memo.md && echo "--- Schipper sentence ---" && grep -o "returns a statistic of [^.]*\." outputs/research_memo.md && echo "--- size sentence (sec 5) ---" && grep -o "Firm size must be read carefully[^.]*\.\( [^.]*\.\)\?" outputs/research_memo.md | head -1
Done. n_valid_events = 35 rho_bar = 0.0057 hac_lag = 3 cal n_days = 230 === wc === 1384 outputs/research_memo.md --- Schipper sentence --- returns a statistic of 25. --- size sentence (sec 5) --- Firm size must be read carefully: in raw percentage terms larger, more diversified manufacturers tend to absorb a single recall more easily, yet because they are also less volatile their *risk-adjusted* (standardized) reaction can actually look larger, so size is not a simple proxy for resilience. In short, product recalls in the toy industry are a clear, fast, and economically meaningful negative signal, priced efficiently enough that the principal beneficiaries of safety improvements are long-horizon shareholders and consumers rather than short-horizon traders.
cd /app && grep -o "on 3 degrees of freedom ([^)]*)" outputs/research_memo.md
on 3 degrees of freedom (p = < 0.0001)
command: str_replace
path: /app/analysis.R
old_str: fmt_p <- function(p) if (p < 0.0001) "< 0.0001" else sprintf("%.4f", p)
new_str: fmt_p <- function(p) if (p < 0.0001) "< 0.0001" else sprintf("%.4f", p)
fmt_pv <- function(p) if (p < 0.0001) "p < 0.0001" else sprintf("p = %.4f", p)The file /app/analysis.R has been edited successfully.
command: str_replace
path: /app/analysis.R
old_str: "zero, returns a statistic of ", sprintf("%.2f", wald_stat), " on 3 degrees of freedom (p = ",
fmt_p(wald_p), "), ", if (wald_p < 0.05) "decisively rejecting" else "failing to reject",
new_str: "zero, returns a statistic of ", sprintf("%.2f", wald_stat), " on 3 degrees of freedom (",
fmt_pv(wald_p), "), ", if (wald_p < 0.05) "decisively rejecting" else "failing to reject",The file /app/analysis.R has been edited successfully.
cd /app && rm -rf outputs && mkdir -p outputs && Rscript analysis.R 2>&1 && grep -o "on 3 degrees of freedom ([^)]*)" outputs/research_memo.md && wc -w outputs/research_memo.md
Done. n_valid_events = 35 rho_bar = 0.0057 hac_lag = 3 cal n_days = 230 on 3 degrees of freedom (p < 0.0001) 1383 outputs/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.01163,
"patell_z": -5.984886,
"bmp_t": -4.992138,
"kp_t": -4.570158,
"pct_negative": 0.828571,
"n": 35
},
"window_2day": {
"mean_scar": -0.862243,
"patell_z": -5.101097,
"bmp_t": -4.509969,
"kp_t": -4.128747,
"pct_negative": 0.8,
"n": 35
},
"window_11day": {
"mean_scar": -0.450723,
"patell_z": -2.666514,
"bmp_t": -2.174875,
"kp_t": -1.991035,
"pct_negative": 0.628571,
"n": 35
}
},
"cross_section_hac": {
"intercept": 6.870415,
"log_units": -0.277206,
"media": -0.140035,
"severity": -0.049356,
"log_mcap": -0.349665,
"se_intercept": 1.989976,
"se_log_units": 0.143768,
"se_media": 0.045345,
"se_severity": 0.079685,
"se_log_mcap": 0.109201,
"r_squared": 0.365807,
"n_obs": 35,
"hac_lag": 3
},
"cross_section_wls": {
"intercept": 6.181414,
"log_units": -0.245301,
"media": -0.142987,
"severity": -0.068882,
"log_mcap": -0.301826,
"se_intercept": 2.373976,
"se_log_units": 0.119944,
"se_media": 0.063018,
"se_severity": 0.074244,
"se_log_mcap": 0.192047,
"r_squared": 0.307908,
"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.628867,
"wald_p": 1.1e-05,
"df": 3
}
}cd /app && rm -rf outputs && Rscript analysis.R 2>&1; echo "EXIT CODE: $?"; echo "=== Output files ==="; ls -la outputs/
Done. n_valid_events = 35 rho_bar = 0.0057 hac_lag = 3 cal n_days = 230 EXIT CODE: 0 === Output files === total 165 drwxr-sr-x 2 h2tagent h2tagent 4096 Jun 20 18:08 . drwxrws--- 4 h2tagent h2tagent 4096 Jun 20 18:08 .. -rw-r--r-- 1 h2tagent h2tagent 53030 Jun 20 18:08 car_timeline.png -rw-r--r-- 1 h2tagent h2tagent 3619 Jun 20 18:08 event_cars.csv -rw-r--r-- 1 h2tagent h2tagent 1839 Jun 20 18:08 event_study_results.json -rw-r--r-- 1 h2tagent h2tagent 90945 Jun 20 18:08 portfolio_comparison.png -rw-r--r-- 1 h2tagent h2tagent 9243 Jun 20 18:08 research_memo.md
cd /app && cp outputs/event_study_results.json /tmp/run1.json && cp outputs/event_cars.csv /tmp/run1.csv && rm -rf outputs && Rscript analysis.R >/dev/null 2>&1 && diff -q /tmp/run1.json outputs/event_study_results.json && diff -q /tmp/run1.csv outputs/event_cars.csv && echo "DETERMINISTIC: JSON and CSV identical across runs"
DETERMINISTIC: JSON and CSV identical across runs
cd /app && sed -n '1,90p' analysis.R
suppressPackageStartupMessages({
library(jsonlite)
library(ggplot2)
})
# =====================================================================
# Product Recall Stock-Price Event Study
# Deterministic modern event-study pipeline (base/statistical primitives)
# =====================================================================
EST_LEN <- 200 # estimation-window length (trading days)
EST_GAP <- 30 # gap (trading days) between estimation window and event
round6 <- function(x) if (is.numeric(x) && !is.integer(x)) round(x, 6) else x
rlist <- function(l) lapply(l, round6)
# =====================================================================
# 1. Load and clean
# - drop NAs, sentinel returns (return < -10), duplicates
# - sort by (firm_id, date)
# =====================================================================
returns <- read.csv("/app/data/stock_returns.csv", stringsAsFactors = FALSE)
recalls <- read.csv("/app/data/recalls.csv", stringsAsFactors = FALSE)
firms <- read.csv("/app/data/firms.csv", stringsAsFactors = FALSE)
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))
# Global trading-day calendar (union of all firm dates), 0-based index
all_dates <- sort(unique(returns$date))
n_dates <- length(all_dates)
date_to_idx <- setNames(seq_along(all_dates) - 1L, as.character(all_dates))
# Per-firm fast lookups: named numeric vectors keyed by date string
firm_ids <- sort(unique(returns$firm_id))
firm_data <- list(); ret_vec <- list(); mkt_vec <- list()
for (f in firm_ids) {
d <- returns[returns$firm_id == f, c("date", "return", "market_return")]
d <- d[order(d$date), ]
firm_data[[f]] <- d
ret_vec[[f]] <- setNames(d$return, as.character(d$date))
mkt_vec[[f]] <- setNames(d$market_return, as.character(d$date))
}
# Market return by date (constant across firms on a given date)
mkt_by_date <- tapply(returns$market_return, as.character(returns$date), function(x) x[1])
# =====================================================================
# 2. Market model + prediction-error-corrected SAR / SCAR
# =====================================================================
# Estimation window: 200 trading days ending 30 trading days before event,
# i.e. calendar indices [eidx-EST_GAP-EST_LEN, eidx-EST_GAP-1]. Require >=100 obs.
event_market_model <- function(fid, eidx) {
est_end <- eidx - EST_GAP - 1L
est_start <- est_end - EST_LEN + 1L
if (est_start < 0) return(NULL)
est_dates <- as.character(all_dates[(est_start + 1L):(est_end + 1L)])
rv <- ret_vec[[fid]][est_dates]; mv <- mkt_vec[[fid]][est_dates]
ok <- !is.na(rv) & !is.na(mv)
rv <- rv[ok]; mv <- mv[ok]
if (length(rv) < 100) return(NULL)
m <- lm(rv ~ mv)
cf <- coef(m)
sig <- summary(m)$sigma # residual SE with (n-2) df
mrm <- mean(mv)
list(alpha = unname(cf[1]), beta = unname(cf[2]), sigma = sig,
n_est = length(rv), mean_rm = mrm, ss_rm = sum((mv - mrm)^2),
est_dates = est_dates[ok])
}
windows <- list(w3 = c(-1L, 1L), w2 = c(0L, 1L), w11 = c(-5L, 5L))
# Patell prediction-error-corrected SCAR over an event window.
# Var(CAR) = sigma^2 * sum_t [ 1 + 1/T + (Rm_t - mean_Rm)^2 / SS_Rm ]
window_scar <- function(m, eidx, w) {
offs <- seq.int(w[1], w[2])command: view path: /app/outputs/car_timeline.png
<output_image> …[truncated]
command: view path: /app/outputs/portfolio_comparison.png
<output_image> …[truncated]
No file changes, the agent left the workspace untouched.
# SyncVals normalized verifier summary # task: product-recall-stock-price-event # attempt: 3 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). ---------------------------------------------------------------------- <output_image> …[truncated]
Reproduce this trial: git checkout 2f94510 && PYTHONPATH=src python3 scripts/build_site.py , then open trial/trial_5fe77f1e1c4b4699. Re-running the agent live requires EVAL_PLATFORM_ENABLE_OAUTH_SMOKE=1 and is non-deterministic.
Trial trial_5fe77f1e1c4b4699 · verifier authoritative; classifier explanatory.