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 -1
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/data && echo "===STOCK_RETURNS===" && head -5 stock_returns.csv && echo "..." && wc -l stock_returns.csv && echo "===RECALLS===" && head -5 recalls.csv && wc -l recalls.csv && echo "===FIRMS===" && head -5 firms.csv && wc -l 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 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 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 firms.csv
cd /app/data && echo "===FULL FIRMS===" && cat firms.csv && echo "" && echo "===FULL RECALLS===" && cat recalls.csv
===FULL 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 FIRM_005,173.95,3944,1.4716,-0.000333,0.0235,3 FIRM_006,378.94,3944,1.3716,0.000584,0.018,0 FIRM_007,2107.82,3944,0.7672,-0.000741,0.0203,2 FIRM_008,1237.08,3942,1.2161,-6.7e-05,0.0162,3 FIRM_009,1771.95,3944,1.1583,0.000181,0.0155,0 FIRM_010,649.59,3942,1.2093,0.000393,0.0156,2 FIRM_011,5194.09,3942,1.5357,0.000456,0.0155,1 FIRM_012,4597.88,3944,1.2118,0.000497,0.0152,2 FIRM_013,1957.13,3944,1.4395,-7.4e-05,0.0219,4 FIRM_014,6993.17,3944,1.1338,-0.000131,0.0168,5 FIRM_015,3168.49,3942,1.2446,0.000529,0.0165,1 FIRM_016,644.74,3942,1.4156,4e-06,0.0187,2 FIRM_017,2814.39,3944,0.3714,-0.000538,0.0157,3 FIRM_018,572.12,3942,0.9402,-0.000467,0.0227,1 ===FULL 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 5,FIRM_014,2007-04-24,chemical,67821,13,6.49 6,FIRM_013,2007-05-04,lead_paint,519027,3,5.0 7,FIRM_012,2007-05-08,lead_paint,558179,7,9.42 8,FIRM_014,2007-05-16,chemical,1629059,6,8.69 9,FIRM_001,2007-05-24,choking,11694380,7,3.9 10,FIRM_016,2007-05-30,laceration,1525113,6,5.9 11,FIRM_014,2007-05-31,choking,469277,13,5.41 12,FIRM_014,2007-06-13,choking,2022284,4,6.69 13,FIRM_008,2007-06-14,lead_paint,10627235,9,4.01 14,FIRM_015,2007-06-15,lead_paint,509523,13,3.2 15,FIRM_007,2007-06-20,lead_paint,562028,7,9.21 16,FIRM_001,2007-06-25,lead_paint,5091044,10,9.31 17,FIRM_017,2007-07-09,chemical,1579890,8,8.59 18,FIRM_005,2007-07-13,lead_paint,5817593,5,9.8 19,FIRM_002,2007-07-23,choking,2158016,13,7.7 20,FIRM_012,2007-08-09,laceration,6310122,7,7.88 21,FIRM_005,2007-08-10,laceration,466285,10,7.86 22,FIRM_016,2007-08-13,lead_paint,2163078,7,5.33 23,FIRM_008,2007-08-14,choking,1605804,9,5.11 24,FIRM_001,2007-08-21,burn,355518,10,3.16 25,FIRM_018,2007-08-27,choking,211071,6,6.8 26,FIRM_010,2007-09-04,laceration,6161271,9,3.6 27,FIRM_005,2007-09-07,chemical,1301127,6,3.32 28,FIRM_013,2007-09-18,laceration,475322,8,6.27 29,FIRM_010,2007-09-20,lead_paint,1906732,5,4.69 30,FIRM_001,2007-09-25,choking,11961437,11,2.97 31,FIRM_014,2007-09-27,lead_paint,71974,11,8.34 32,FIRM_008,2007-11-07,choking,233330,11,8.75 33,FIRM_013,2007-11-08,burn,551744,5,2.51 34,FIRM_017,2007-11-09,choking,19715949,7,1.07 35,FIRM_011,2007-11-13,lead_paint,3365377,12,4.03
cd /app && cat -n analysis.R
1 suppressPackageStartupMessages({
2 library(jsonlite)
3 library(ggplot2)
4 })
5
6 EST_LEN <- 200
7 EST_GAP <- 30
8
9 # =====================================================================
10 # 1. Load and clean
11 # =====================================================================
12 returns <- read.csv("/app/data/stock_returns.csv")
13 recalls <- read.csv("/app/data/recalls.csv")
14 firms <- read.csv("/app/data/firms.csv")
15
16 returns <- returns[!is.na(returns$return) & !is.na(returns$market_return), ]
17 returns <- returns[!duplicated(returns), ]
18 returns$date <- as.Date(returns$date)
19 returns <- returns[order(returns$firm_id, returns$date), ]
20 rownames(returns) <- NULL
21
22 recalls <- recalls[!duplicated(recalls), ]
23 recalls$date <- as.Date(recalls$date)
24
25 firms <- firms[!duplicated(firms), ]
26
27 n_events <- nrow(recalls)
28 n_firms <- nrow(firms)
29 n_firms_with_recalls <- length(unique(recalls$firm_id))
30
31 all_dates <- sort(unique(returns$date))
32 date_to_idx <- setNames(seq_along(all_dates) - 1L, as.character(all_dates))
33
34 # =====================================================================
35 # 2. Market model , basic OLS, returns raw AR (no Patell standardization)
36 # =====================================================================
37 event_market_model <- function(fid, eidx) {
38 est_end <- eidx - EST_GAP - 1
39 est_start <- est_end - EST_LEN + 1
40 if (est_start < 0) return(NULL)
41 est_dates <- all_dates[(est_start + 1):(est_end + 1)]
42 sub <- returns[returns$firm_id == fid & returns$date %in% est_dates, ]
43 if (nrow(sub) < 100) return(NULL)
44 m <- lm(return ~ market_return, data = sub)
45 list(alpha = unname(coef(m)[1]), beta = unname(coef(m)[2]),
46 sigma_eps = sd(resid(m)), n_est = nrow(sub),
47 mean_rm = mean(sub$market_return),
48 sum_sq_dev_rm = sum((sub$market_return - mean(sub$market_return))^2))
49 }
50
51 windows <- list(w3 = c(-1, 1), w2 = c(0, 1), w11 = c(-5, 5))
52
53 event_rows <- list()
54 daily_long <- list()
55
56 for (i in seq_len(n_events)) {
57 fid <- recalls$firm_id[i]
58 edate <- recalls$date[i]
59 estr <- as.character(edate)
60 if (!(estr %in% names(date_to_idx))) next
61 eidx <- as.integer(date_to_idx[estr])
62
63 m <- event_market_model(fid, eidx)
64 if (is.null(m)) next
65
66 firm <- returns[returns$firm_id == fid, ]
67 rownames(firm) <- as.character(firm$date)
68
69 cars <- list(); ar_day0 <- NA_real_; valid_w3 <- TRUE
70 for (wname in names(windows)) {
71 w <- windows[[wname]]; ars <- numeric(0); ok <- TRUE
72 for (off in seq.int(w[1], w[2])) {
73 tidx <- eidx + off
74 if (tidx < 0 || tidx >= length(all_dates)) { ok <- FALSE; break }
75 target <- all_dates[tidx + 1]
76 if (!(as.character(target) %in% rownames(firm))) { ok <- FALSE; break }
77 rm_t <- firm[as.character(target), "market_return"]
78 ret_t <- firm[as.character(target), "return"]
79 ar <- ret_t - (m$alpha + m$beta * rm_t)
80 ars <- c(ars, ar)
81 if (wname == "w3" && off == 0) ar_day0 <- ar
82 }
83 if (!ok) {
84 if (wname == "w3") valid_w3 <- FALSE
85 cars[[wname]] <- NA_real_
86 } else {
87 # NOTE: simple summation of raw ARs , spec wants standardized SCAR
88 cars[[wname]] <- sum(ars)
89 }
90 }
91 if (!valid_w3 || is.na(cars$w3)) next
92
93 event_rows[[length(event_rows) + 1L]] <- data.frame(
94 event_id = as.integer(recalls$event_id[i]),
95 firm_id = fid,
96 date = estr,
97
…[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:", sum(is.na(returns$market_return)), "\n")
cat("Sentinel (<-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(table(returns$firm_id))
cat("Per-firm obs after cleaning:\n")
r2 <- returns[!is.na(returns$return) & !is.na(returns$market_return) & returns$return >= -10,]
r2 <- r2[!duplicated(r2),]
print(table(r2$firm_id))
'Total rows: 9364
NA return: 0
NA market: 3
Sentinel (<-10): 5
Duplicated rows: 4
Unique firms: 18
Date range: 2006-01-03 2007-12-31
FIRM_001 FIRM_002 FIRM_003 FIRM_004 FIRM_005 FIRM_006 FIRM_007 FIRM_008
520 520 520 520 520 520 520 520
FIRM_009 FIRM_010 FIRM_011 FIRM_012 FIRM_013 FIRM_014 FIRM_015 FIRM_016
520 521 520 520 520 520 521 521
FIRM_017 FIRM_018
520 521
Per-firm obs after cleaning:
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 '
for (p in c("sandwich","lmtest","jsonlite","ggplot2")) {
cat(p, ":", requireNamespace(p, quietly=TRUE), "\n")
}
'sandwich : FALSE lmtest : FALSE jsonlite : TRUE ggplot2 : TRUE
cd /app && Rscript -e '
returns <- read.csv("/app/data/stock_returns.csv")
r2 <- returns[!is.na(returns$return) & !is.na(returns$market_return) & returns$return >= -10,]
r2 <- r2[!duplicated(r2),]
r2$date <- as.Date(r2$date)
all_dates <- sort(unique(r2$date))
cat("N unique dates (global calendar):", length(all_dates), "\n")
# check per firm how many of global dates present
firms <- unique(r2$firm_id)
for (f in firms[1:5]) {
d <- r2$date[r2$firm_id==f]
cat(f, "n=", length(d), " missing-from-global=", length(setdiff(all_dates, d)), "\n")
}
# Is market_return identical across firms on a given date?
library(stats)
d1 <- all_dates[250]
sub <- r2[r2$date==d1,]
cat("On", as.character(d1), "market_return unique vals:", length(unique(round(sub$market_return,8))), "range firms:", nrow(sub), "\n")
'N unique dates (global calendar): 520 FIRM_004 n= 519 missing-from-global= 1 FIRM_008 n= 520 missing-from-global= 0 FIRM_017 n= 519 missing-from-global= 1 FIRM_018 n= 520 missing-from-global= 0 FIRM_015 n= 518 missing-from-global= 2 On 2006-12-18 market_return unique vals: 1 range firms: 18
cd /app && Rscript -e '
returns <- read.csv("/app/data/stock_returns.csv")
recalls <- read.csv("/app/data/recalls.csv")
r2 <- returns[!is.na(returns$return) & !is.na(returns$market_return) & returns$return >= -10,]
r2 <- r2[!duplicated(r2),]
r2$date <- as.Date(r2$date); recalls$date <- as.Date(recalls$date)
all_dates <- sort(unique(r2$date))
date_to_idx <- setNames(seq_along(all_dates)-1L, as.character(all_dates))
cat("Ndates:", length(all_dates), "\n")
idxs <- date_to_idx[as.character(recalls$date)]
cat("events with date in calendar:", sum(!is.na(idxs)), "of", nrow(recalls), "\n")
cat("min event idx:", min(idxs, na.rm=TRUE), " (need >=230 for est window)\n")
cat("max event idx:", max(idxs, na.rm=TRUE), " (need <=514 for +5 window; <=489 for +30)\n")
# For each event check est window start>=0 and +5 <= last and +30
res <- data.frame(event_id=recalls$event_id, idx=as.integer(idxs))
res$est_ok <- (res$idx - 230) >= 0
res$w11_ok <- (res$idx + 5) <= (length(all_dates)-1)
res$w30_ok <- (res$idx + 30) <= (length(all_dates)-1)
print(res)
cat("est_ok:", sum(res$est_ok, na.rm=T), " w11_ok:", sum(res$w11_ok,na.rm=T), " w30_ok:", sum(res$w30_ok,na.rm=T), "\n")
'Ndates: 520 events with date in calendar: 35 of 35 min event idx: 316 (need >=230 for est window) max event idx: 485 (need <=514 for +5 window; <=489 for +30) event_id idx est_ok w11_ok w30_ok 1 1 316 TRUE TRUE TRUE 2 2 321 TRUE TRUE TRUE 3 3 334 TRUE TRUE TRUE 4 4 338 TRUE TRUE TRUE 5 5 340 TRUE TRUE TRUE 6 6 348 TRUE TRUE TRUE 7 7 350 TRUE TRUE TRUE 8 8 356 TRUE TRUE TRUE 9 9 362 TRUE TRUE TRUE 10 10 366 TRUE TRUE TRUE 11 11 367 TRUE TRUE TRUE 12 12 376 TRUE TRUE TRUE 13 13 377 TRUE TRUE TRUE 14 14 378 TRUE TRUE TRUE 15 15 381 TRUE TRUE TRUE 16 16 384 TRUE TRUE TRUE 17 17 394 TRUE TRUE TRUE 18 18 398 TRUE TRUE TRUE 19 19 404 TRUE TRUE TRUE 20 20 417 TRUE TRUE TRUE 21 21 418 TRUE TRUE TRUE 22 22 419 TRUE TRUE TRUE 23 23 420 TRUE TRUE TRUE 24 24 425 TRUE TRUE TRUE 25 25 429 TRUE TRUE TRUE 26 26 435 TRUE TRUE TRUE 27 27 438 TRUE TRUE TRUE 28 28 445 TRUE TRUE TRUE 29 29 447 TRUE TRUE TRUE 30 30 450 TRUE TRUE TRUE 31 31 452 TRUE TRUE TRUE 32 32 481 TRUE TRUE TRUE 33 33 482 TRUE TRUE TRUE 34 34 483 TRUE TRUE TRUE 35 35 485 TRUE TRUE TRUE est_ok: 35 w11_ok: 35 w30_ok: 35
cd /app && Rscript -e '
N <- 35
cat("HAC L = floor(4*(N/100)^(2/9)) =", floor(4*(N/100)^(2/9)), "\n")
for (N in c(30,31,32,33,34,35)) cat(" N=",N," L=",floor(4*(N/100)^(2/9)),"\n")
'HAC L = floor(4*(N/100)^(2/9)) = 3 N= 30 L= 3 N= 31 L= 3 N= 32 L= 3 N= 33 L= 3 N= 34 L= 3 N= 35 L= 3
command: create
path: /app/analysis.R
file_text: suppressPackageStartupMessages({
library(jsonlite)
library(ggplot2)
})
EST_LEN <- 200 # estimation window length (trading days)
EST_GAP <- 30 # gap (trading days) between estimation window end and event
# =====================================================================
# 1. Load and clean
# remove NAs, sentinel returns (return < -10), duplicates; sort.
# =====================================================================
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, ] # drop sentinel returns
returns <- returns[!duplicated(returns), ] # drop duplicate rows
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 (0-based index) from the cleaned panel
all_dates <- sort(unique(returns$date))
n_all <- length(all_dates)
date_to_idx <- setNames(seq_along(all_dates) - 1L, as.character(all_dates))
# Per-firm panels with date rownames for O(1) lookup
firm_panel <- list()
for (f in unique(returns$firm_id)) {
sub <- returns[returns$firm_id == f, c("date", "return", "market_return")]
sub <- sub[order(sub$date), ]
rownames(sub) <- as.character(sub$date)
firm_panel[[f]] <- sub
}
# =====================================================================
# 2. Market model (OLS) + Patell prediction-error-corrected SAR / SCAR
# =====================================================================
# Estimation window: 200 days ending 30 trading days before the event.
# est_end = eidx - EST_GAP - 1 ; est_start = est_end - EST_LEN + 1
fit_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)]
fp <- firm_panel[[fid]]
sub <- fp[as.character(est_dates)[as.character(est_dates) %in% rownames(fp)], ]
if (nrow(sub) < 100) return(NULL)
m <- lm(return ~ market_return, data = sub)
cf <- coef(m)
mean_rm <- mean(sub$market_return)
ss_rm <- sum((sub$market_return - mean_rm)^2)
list(alpha = unname(cf[1]), beta = unname(cf[2]),
S = summary(m)$sigma, # residual std error, (n-2) df
n_est = nrow(sub), mean_rm = mean_rm, ss_rm = ss_rm,
est_dates = as.character(sub$date))
}
windows <- list(w3 = c(-1, 1), w2 = c(0, 1), w11 = c(-5, 5))
# Pre-fit a market model for every event (reused across sections)
emods <- vector("list", n_events)
for (i in seq_len(n_events)) {
estr <- as.character(recalls$date[i])
if (!(estr %in% names(date_to_idx))) next
eidx <- as.integer(date_to_idx[estr])
emods[[i]] <- fit_market_model(recalls$firm_id[i], eidx)
}
event_rows <- list()
for (i in seq_len(n_events)) {
fid <- recalls$firm_id[i]
estr <- as.character(recalls$date[i])
if (!(estr %in% names(date_to_idx))) next
eidx <- as.integer(date_to_idx[estr])
m <- emods[[i]]
if (is.null(m)) next
fp <- firm_panel[[fid]]
scars <- list(); ar_day0 <- NA_real_; valid_w3 <- TRUE
for (wname in names(windows)) {
w <- windows[[wname]]; ars <- numeric(0); factsum <- 0; ok <- TRUE
for (off in seq.int(w[1], w[2])) {
tidx <- eidx + off
if (tidx < 0 || tidx >= n_all) { ok <- FALSE; break }
target <- as.character(all_dates[tidx + 1])
if (!(target %in% rownames(fp))) { ok <- F
…[truncated]Existing file was successfully overwritten at /app/analysis.R
cd /app && rm -f outputs/* && Rscript analysis.R 2>&1 | tail -20
Done. n_valid_events = 35 rho_bar = 0.0057 HAC L = 3 calendar 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.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 && echo "=== event_cars.csv ===" && cat outputs/event_cars.csv && echo "" && echo "rows:" && wc -l outputs/event_cars.csv
=== event_cars.csv === "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 4,"FIRM_013","2007-04-20",-0.275920692089554,-0.623000766624633,-0.852290011168427,-0.0130106860489592 5,"FIRM_014","2007-04-24",-0.933499846911045,-0.478116395743624,-0.884830134388866,0.00353526947807872 6,"FIRM_013","2007-05-04",-0.699967938020095,-0.717461883024859,-0.720466366124244,-0.021564533708219 7,"FIRM_012","2007-05-08",-3.07578065705761,-2.1975855110466,-2.28473374027615,-0.0455965842172699 8,"FIRM_014","2007-05-16",-1.29153221379547,-1.08677329850404,0.648316407005498,-0.0251958872761519 9,"FIRM_001","2007-05-24",-0.231563920337818,-0.488734256774204,-0.781637012748103,-0.000158136631980284 10,"FIRM_016","2007-05-30",-1.0907326752555,-1.30982209832501,0.130695274334959,-0.0398537195566817 11,"FIRM_014","2007-05-31",-0.135533412480562,0.275393250750628,-1.03403112488425,-0.00545785663987496 12,"FIRM_014","2007-06-13",-1.46026903774329,-0.562521069887002,-1.21385827372089,-0.00533259749050864 13,"FIRM_008","2007-06-14",-2.1901311278821,-2.21345170787082,-1.88952684155481,-0.0156547598068808 14,"FIRM_015","2007-06-15",-1.6151913610164,-1.09224023649714,0.173498150983117,-0.00820698455060612 15,"FIRM_007","2007-06-20",-0.334428791672922,0.403422504581258,-1.89259283747357,-8.28115100908744e-05 16,"FIRM_001","2007-06-25",-1.5019438438818,-1.21473636836881,0.823858841851977,-0.012460597430672 17,"FIRM_017","2007-07-09",-0.238601130896314,-0.571134920352445,1.6957208326185,0.00339645935392437 18,"FIRM_005","2007-07-13",0.677063102053534,0.547341737350446,1.34454606572894,0.0254457913382137 19,"FIRM_002","2007-07-23",-1.80929451027931,-1.03297100312427,-0.358897721868724,-0.0156646257764308 20,"FIRM_012","2007-08-09",-1.66213527824235,-1.11783474494777,-2.15932695355525,-0.0256075080789634 21,"FIRM_005","2007-08-10",-0.456194137298658,-0.799298584389155,0.0448270811470582,-0.000755717037022503 22,"FIRM_016","2007-08-13",-1.49244691804546,-1.74305216171242,0.114659223920113,-0.0429491684916863 23,"FIRM_008","2007-08-14",0.115130111070156,0.336166986604979,-0.155033296963885,-0.00828904542054529 24,"FIRM_001","2007-08-21",-1.80870149953568,-1.99742040515473,-2.12875515536391,-0.0223591044581077 25,"FIRM_018","2007-08-27",0.910154974750102,0.606777890905141,-0.079992542373074,-0.0322299501224439 26,"FIRM_010","2007-09-04",-2.42633585931016,-2.61349621580626,-1.00256859163589,-0.0455981528646128 27,"FIRM_005","2007-09-07",-0.217591994959607,-0.469448838771382,1.03618790018046,-0.0218095765835027 28,"FIRM_013","2007-09-18",0.115762390304849,-0.0193596673312326,0.40174160447564,-0.0140641553352069 29,"FIRM_010","2007-09-20",-0.335164733434028,-1.00687621094432,-0.0511144535844723,-0.0131417902804066 30,"FIRM_001","2007-09-25",-0.842169452594298,-0.314331103467953,-2.89043355574195,0.0058276032465391 31,"FIRM_014","2007-09-27",-2.95574580142152,-2.99181770115736,-0.22289705997929,-0.0283779691766043 32,"FIRM_008","2007-11-07",-2.17989808285356,-2.30035752328721,0.678901144115882,-0.02242146558036 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
cd /app && Rscript -e '
suppressPackageStartupMessages(library(jsonlite))
ec <- read.csv("/app/outputs/event_cars.csv", stringsAsFactors=FALSE)
s3 <- ec$scar_3day
N <- length(s3)
cat("--- Aggregate cross-check (3-day) ---\n")
cat("mean:", mean(s3), " patell:", sum(s3)/sqrt(N), " bmp:", mean(s3)/(sd(s3)/sqrt(N)), "\n")
rho <- 0.005682
cat("kp:", mean(s3)/sqrt(var(s3)*(1+(N-1)*rho)/N), "\n")
cat("pct_neg:", mean(s3<0), "\n")
cat("\n--- WLS cross-check via lm(weights) ---\n")
recalls <- read.csv("/app/data/recalls.csv"); firms <- read.csv("/app/data/firms.csv")
cs <- merge(ec, 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),]
w <- 1/cs$idio_vol^2
mw <- lm(scar_3day ~ log_units+media_articles+severity_score+log_mcap, data=cs, weights=w)
sw <- summary(mw)
print(round(sw$coefficients[,1:2],6))
cat("wls R2:", sw$r.squared, "\n")
cat("\n--- OLS (HAC point est & R2) via lm ---\n")
mo <- lm(scar_3day ~ log_units+media_articles+severity_score+log_mcap, data=cs)
cat("ols R2:", summary(mo)$r.squared, "\n")
print(round(coef(mo),6))
'--- Aggregate cross-check (3-day) ---
mean: -1.01163 patell: -5.984886 bmp: -4.992138
kp: -4.570168
pct_neg: 0.8285714
--- WLS cross-check via lm(weights) ---
Estimate Std. Error
(Intercept) 6.181414 2.373976
log_units -0.245301 0.119944
media_articles -0.142987 0.063018
severity_score -0.068882 0.074244
log_mcap -0.301826 0.192047
wls R2: 0.3079082
--- OLS (HAC point est & R2) via lm ---
ols R2: 0.365807
(Intercept) log_units media_articles severity_score log_mcap
6.870415 -0.277206 -0.140035 -0.049356 -0.349665cd /app && Rscript -e '
ec <- 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(ec, 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)
XtXi <- solve(t(X)%*%X); b <- XtXi%*%t(X)%*%y; u <- as.numeric(y - X%*%b)
L <- floor(4*(N/100)^(2/9))
# brute-force meat with explicit weighted sum over lags and observation pairs
meat <- matrix(0,k,k)
for (t in 1:N) meat <- meat + u[t]^2 * (X[t,] %o% X[t,])
for (l in 1:L) {
wl <- 1 - l/(L+1)
for (t in (l+1):N) {
term <- (X[t,] %o% X[t-l,]) * (u[t]*u[t-l])
meat <- meat + wl*(term + t(term))
}
}
V <- XtXi %*% meat %*% XtXi
cat("Brute-force HAC SE (L=",L,"):\n"); print(round(sqrt(diag(V)),6))
cat("\nJSON HAC SE:\n")
library(jsonlite); j <- fromJSON("/app/outputs/event_study_results.json")
print(unlist(j$cross_section_hac[c("se_intercept","se_log_units","se_media","se_severity","se_log_mcap")]))
'Brute-force HAC SE (L= 3 ):
[1] 1.989976 0.143768 0.045345 0.079685 0.109201
JSON HAC SE:
se_intercept se_log_units se_media se_severity se_log_mcap
1.989976 0.143768 0.045345 0.079685 0.109201cd /app && Rscript -e '
returns <- read.csv("/app/data/stock_returns.csv", stringsAsFactors=FALSE)
recalls <- read.csv("/app/data/recalls.csv", stringsAsFactors=FALSE)
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)); n_all <- length(all_dates)
d2i <- setNames(seq_along(all_dates)-1L, as.character(all_dates))
EST_LEN<-200; EST_GAP<-30
fp <- split(returns, returns$firm_id)
for(f in names(fp)){ rownames(fp[[f]])<-as.character(fp[[f]]$date) }
# ---- Cowan independent ----
p_hat<-c(); I_pos<-c()
for(i in 1:nrow(recalls)){
fid<-recalls$firm_id[i]; estr<-as.character(recalls$date[i]); eidx<-as.integer(d2i[estr])
est_end<-eidx-EST_GAP-1; est_start<-est_end-EST_LEN+1
est_dates<-as.character(all_dates[(est_start+1):(est_end+1)])
sub<-fp[[fid]][est_dates[est_dates%in%rownames(fp[[fid]])],]
m<-lm(return~market_return,data=sub); a<-coef(m)[1]; bt<-coef(m)[2]
est_ar <- sub$return-(a+bt*sub$market_return)
if(length(est_ar)<50) next
p_hat<-c(p_hat, mean(est_ar>0))
pos<-FALSE
for(off in -1:1){ tgt<-as.character(all_dates[eidx+off+1]); if(tgt%in%rownames(fp[[fid]])){ ar<-fp[[fid]][tgt,"return"]-(a+bt*fp[[fid]][tgt,"market_return"]); if(ar>0) pos<-TRUE } }
I_pos<-c(I_pos, as.integer(pos))
}
N<-length(p_hat); pbar<-mean(p_hat); fp_<-mean(I_pos)
z<-(fp_-pbar)/sqrt(pbar*(1-pbar)/N)
cat("Cowan: N=",N," p_bar=",round(pbar,6)," frac_pos=",round(fp_,6)," z=",round(z,6)," p=",round(2*(1-pnorm(abs(z))),6),"\n")
cat(" n events with >=1 positive AR day in [-1,1]:",sum(I_pos),"of",N,"\n")
# ---- Corrado independent ----
K<-c()
for(i in 1:nrow(recalls)){
fid<-recalls$firm_id[i]; eidx<-as.integer(d2i[as.character(recalls$date[i])])
wd<-c(); wr<-c()
for(off in -30:30){ ti<-eidx+off; if(ti<0||ti>=n_all) next; tgt<-as.character(all_dates[ti+1]); if(tgt%in%rownames(fp[[fid]])){ wd<-c(wd,tgt); wr<-c(wr,fp[[fid]][tgt,"return"]) } }
n<-length(wr); if(n<2) next
rk<-rank(wr); names(rk)<-wd; mr<-(n+1)/2; sr<-sd(rk)
ctr<-c(); for(off in -1:1){ ti<-eidx+off; tgt<-as.character(all_dates[ti+1]); if(!is.na(tgt)&&tgt%in%names(rk)) ctr<-c(ctr,(rk[[tgt]]-mr)/sr) }
if(length(ctr)>0) K<-c(K,mean(ctr))
}
Nc<-length(K); z<-mean(K)/(sd(K)/sqrt(Nc))
cat("Corrado: N=",Nc," z=",round(z,6)," p=",round(2*(1-pnorm(abs(z))),6),"\n")
'Cowan: N= 35 p_bar= 0.492859 frac_pos= 0.514286 z= 0.253547 p= 0.799846 n events with >=1 positive AR day in [-1,1]: 18 of 35 Corrado: N= 35 z= -2.426518 p= 0.015244
cd /app && Rscript -e '
returns <- read.csv("/app/data/stock_returns.csv", stringsAsFactors=FALSE)
recalls <- read.csv("/app/data/recalls.csv", stringsAsFactors=FALSE)
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)); n_all<-length(all_dates)
d2i <- setNames(seq_along(all_dates)-1L, as.character(all_dates))
# rho_bar independent
fp <- split(returns, returns$firm_id)
res<-list()
for(f in names(fp)){ x<-fp[[f]]; if(nrow(x)<30) next; m<-lm(return~market_return,data=x); res[[f]]<-setNames(resid(m),as.character(x$date)) }
nm<-names(res); vals<-c()
for(a in 1:(length(nm)-1)) for(b in (a+1):length(nm)){ ra<-res[[nm[a]]]; rb<-res[[nm[b]]]; cm<-intersect(names(ra),names(rb)); if(length(cm)<20) next; vals<-c(vals,cor(ra[cm],rb[cm])) }
cat("rho_bar =",round(mean(vals),6)," n_pairs=",length(vals)," (expected 153)\n")
# Patell SCAR hand-check for event 1
i<-1; fid<-recalls$firm_id[i]; eidx<-as.integer(d2i[as.character(recalls$date[i])])
est_end<-eidx-31; est_start<-est_end-199
ed<-as.character(all_dates[(est_start+1):(est_end+1)])
x<-fp[[fid]]; rownames(x)<-as.character(x$date); sub<-x[ed[ed%in%rownames(x)],]
m<-lm(return~market_return,data=sub); a<-coef(m)[1]; bt<-coef(m)[2]
S<-summary(m)$sigma; nest<-nrow(sub); mrm<-mean(sub$market_return); ssrm<-sum((sub$market_return-mrm)^2)
# 3-day window
ars<-c(); fsum<-0
for(off in -1:1){ tgt<-as.character(all_dates[eidx+off+1]); rm_t<-x[tgt,"market_return"]; ret<-x[tgt,"return"]; ars<-c(ars,ret-(a+bt*rm_t)); fsum<-fsum+1+1/nest+(rm_t-mrm)^2/ssrm }
scar<-sum(ars)/(S*sqrt(fsum))
cat("Event1 hand SCAR_3day =",round(scar,6)," (JSON -2.773854); n_est=",nest,"\n")
# Schipper-Thompson
ec<-read.csv("/app/outputs/event_cars.csv")
M<-as.matrix(ec[,c("scar_3day","scar_2day","scar_11day")]); Ns<-nrow(M); mb<-colMeans(M); Cv<-cov(M)
W<-as.numeric(Ns * t(mb)%*%solve(Cv)%*%mb)
cat("Schipper Wald =",round(W,6)," p=",signif(pchisq(W,3,lower.tail=FALSE),4),"\n")
'rho_bar = 0.005682 n_pairs= 153 (expected 153) Event1 hand SCAR_3day = -2.773854 (JSON -2.773854); n_est= 200 Schipper Wald = 25.62887 p= 1.141e-05
command: view path: /app/outputs/car_timeline.png
<output_image> …[truncated]
cd /app && Rscript -e 'cat("ggplot2:", as.character(packageVersion("ggplot2")), "\n")'ggplot2: 3.4.1
command: str_replace
path: /app/analysis.R
old_str: labs(title = "Average Cumulative Abnormal Return Around Recall Announcements",
subtitle = "Market-model abnormal returns with 95% confidence bands",
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: labs(title = "Average Cumulative Abnormal Return Around Recall Announcements",
subtitle = "Market-model abnormal returns with 95% confidence bands",
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))
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: labs(title = "Calendar-Time Recall Portfolio vs. Market Cumulative Return",
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: labs(title = "Calendar-Time Recall Portfolio vs. Market Cumulative Return",
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/*.png && Rscript analysis.R 2>&1 | tail -2
Done. n_valid_events = 35 rho_bar = 0.0057 HAC L = 3 calendar 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 && Rscript -e '
returns <- read.csv("/app/data/stock_returns.csv", stringsAsFactors=FALSE)
recalls <- read.csv("/app/data/recalls.csv", stringsAsFactors=FALSE)
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)); n_all<-length(all_dates)
d2i <- setNames(seq_along(all_dates)-1L, as.character(all_dates))
fp <- split(returns, returns$firm_id); for(f in names(fp)) rownames(fp[[f]])<-as.character(fp[[f]]$date)
raw3<-c(); raw2<-c(); raw11<-c(); ar0<-c()
for(i in 1:nrow(recalls)){
fid<-recalls$firm_id[i]; eidx<-as.integer(d2i[as.character(recalls$date[i])])
est_end<-eidx-31; est_start<-est_end-199; ed<-as.character(all_dates[(est_start+1):(est_end+1)])
sub<-fp[[fid]][ed[ed%in%rownames(fp[[fid]])],]; m<-lm(return~market_return,data=sub); a<-coef(m)[1]; bt<-coef(m)[2]
g<-function(w){ s<-0; for(off in w[1]:w[2]){ tgt<-as.character(all_dates[eidx+off+1]); s<-s+(fp[[fid]][tgt,"return"]-(a+bt*fp[[fid]][tgt,"market_return"])) }; s }
raw3<-c(raw3,g(c(-1,1))); raw2<-c(raw2,g(c(0,1))); raw11<-c(raw11,g(c(-5,5)))
t0<-as.character(all_dates[eidx+1]); ar0<-c(ar0, fp[[fid]][t0,"return"]-(a+bt*fp[[fid]][t0,"market_return"]))
}
cat(sprintf("Mean RAW CAR 3-day=%.4f (%.2f%%) 2-day=%.4f 11-day=%.4f\n", mean(raw3),100*mean(raw3), mean(raw2), mean(raw11)))
cat(sprintf("Mean raw AR day0 = %.4f (%.2f%%); median 3-day=%.4f\n", mean(ar0),100*mean(ar0), median(raw3)))
cat(sprintf("t-ratios HAC: log_units=%.2f media=%.2f severity=%.2f log_mcap=%.2f\n", -0.277206/0.143768, -0.140035/0.045345, -0.049356/0.079685, -0.349665/0.109201))
cat(sprintf("Daily alpha=-0.000858 -> annualized ~ %.1f%% (x252)\n", -0.000858*252*100))
'Mean RAW CAR 3-day=-0.0292 (-2.92%) 2-day=-0.0205 11-day=-0.0250 Mean raw AR day0 = -0.0131 (-1.31%); median 3-day=-0.0277 t-ratios HAC: log_units=-1.93 media=-3.09 severity=-0.62 log_mcap=-3.20 Daily alpha=-0.000858 -> annualized ~ -21.6% (x252)
command: str_replace
path: /app/analysis.R
old_str: scars <- list(); ar_day0 <- NA_real_; valid_w3 <- TRUE
for (wname in names(windows)) {
w <- windows[[wname]]; ars <- numeric(0); factsum <- 0; ok <- TRUE
new_str: scars <- list(); raw_cars <- list(); ar_day0 <- NA_real_; valid_w3 <- TRUE
for (wname in names(windows)) {
w <- windows[[wname]]; ars <- numeric(0); factsum <- 0; ok <- TRUEThe file /app/analysis.R has been edited successfully.
command: str_replace
path: /app/analysis.R
old_str: if (!ok) {
if (wname == "w3") valid_w3 <- FALSE
scars[[wname]] <- NA_real_
} else {
car <- sum(ars)
s_car <- m$S * sqrt(factsum) # prediction-error-corrected SD
scars[[wname]] <- car / s_car # standardized CAR
}
}
new_str: if (!ok) {
if (wname == "w3") valid_w3 <- FALSE
scars[[wname]] <- NA_real_; raw_cars[[wname]] <- NA_real_
} else {
car <- sum(ars)
s_car <- m$S * sqrt(factsum) # prediction-error-corrected SD
scars[[wname]] <- car / s_car # standardized CAR
raw_cars[[wname]] <- car # raw cumulative abnormal return
}
}The file /app/analysis.R has been edited successfully.
command: str_replace
path: /app/analysis.R
old_str: scar_11day = scars$w11,
ar_day0 = ar_day0,
eidx = eidx,
new_str: scar_11day = scars$w11,
ar_day0 = ar_day0,
rawcar_3 = raw_cars$w3,
rawcar_2 = raw_cars$w2,
rawcar_11 = raw_cars$w11,
eidx = eidx,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, " rho_bar =", round(rho_bar, 4),
" HAC L =", L, " calendar n_days =", nrow(cal_df), "\n")
new_str: # =====================================================================
# Research memo (regenerated on every run from the computed results)
# =====================================================================
rawcar3 <- mean(event_df$rawcar_3, na.rm = TRUE)
rawcar2 <- mean(event_df$rawcar_2, na.rm = TRUE)
rawcar11 <- mean(event_df$rawcar_11, na.rm = TRUE)
mean_ar0 <- mean(event_df$ar_day0, na.rm = TRUE)
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
alpha_ann <- calendar$alpha * 252 * 100
sig <- function(p) if (p < 0.01) "highly statistically significant" else
if (p < 0.05) "statistically significant at the 5% level" else
if (p < 0.10) "marginally significant (10% level)" else "not statistically significant"
p3 <- 2 * (1 - pnorm(abs(agg_3$patell_z)))
memo <- sprintf(
'# Research Memo: The Stock-Market Impact of Product-Recall Announcements in the Toy Industry
## Executive summary
We study how the equity market reacts when toy manufacturers announce product
recalls. Using a modern event-study design applied to %d recall events across
%d firms (%d of the %d firms in the sample experienced at least one recall), we
find that recalls are associated with an economically large and statistically
robust **negative** stock-price reaction concentrated in the days immediately
surrounding the announcement. The average three-day (-1,+1) cumulative abnormal
return is about **%.2f%%**, and the announcement-day abnormal return alone
averages **%.2f%%**. The effect is pervasive rather than driven by a few
outliers: %.0f%% of events show a negative standardized cumulative abnormal
return (SCAR) over the three-day window. In plain terms, a recall destroys a
meaningful slice of shareholder value almost immediately, and the market
appears to absorb the news quickly.
## 1. Magnitude and statistical significance of abnormal returns
Abnormal returns measure the portion of a stock''s move that cannot be explained
by the overall market (via a firm-specific market model estimated over a
200-trading-day window ending 30 days before the event). Standardizing each
event by its own prediction error makes events comparable.
The mean three-day SCAR is **%.3f** (in standard-deviation units). The formal
tests overwhelmingly reject the hypothesis of no reaction: the Patell z is
**%.2f**, the Boehmer-Musumeci-Poulsen (BMP) t is **%.2f**, and the
Kolari-Pynnonen (KP) cross-correlation-robust t is **%.2f** (two-sided
p < 0.001). The tighter two-day (0,+1) window tells the same story
(mean SCAR %.3f; BMP t %.2f), while the wider eleven-day (-5,+5) window is
weaker but still significant (mean SCAR %.3f; BMP t %.2f). That the signal is
strongest in the narrow windows and decays in the wide window indicates the
information is incorporated rapidly, with little evidence of a continuing slide.
Because the BMP and KP statistics (which allow for event-induced volatility and
cross-event correlation, here rho-bar = %.4f) remain large, the result is not an
artifact of variance or clustering assumptions. The Schipper-Thompson joint Wald
test that all three window means are simultaneously zero is decisively rejected
(chi-square = %.1f on 3 d.f., p < 0.001).
## 2. What drives the cross-sectional heterogeneity?
Not all recalls are punished equally. Regressing the three-day SCAR on recall
and firm characteristics (with heteroskedasticity- and autocorrelation-robust
Newey-West standard errors, lag = %d) explains a substantial share of the
variation (R-squared = %.2f). The economically and statistically important
drivers are:
* **Media coverage** (coefficient %.3f, t = %.2f): the more press articles a
recall generate
…[truncated]The file /app/analysis.R has been edited successfully.
cd /app && rm -f outputs/* && Rscript analysis.R 2>&1 | tail -3
"firms within 30 trading days of a recall and regress its return on the market. The portfolio'" Execution halted
cd /app && grep -n "''" analysis.R
561:Abnormal returns measure the portion of a stock''s move that cannot be explained 615:The portfolio''s alpha is **%.4f per day** (roughly %.1f%% annualized) with a 638:which is not significant. The sign test''s neutrality is itself informative: the
cd /app && python3 - <<'PY'
import re
p='analysis.R'
s=open(p).read()
# switch delimiters: opening
s=s.replace("memo <- sprintf(\n'# Research Memo:", "memo <- sprintf(\n\"# Research Memo:")
# closing delimiter: the line that ends the template then comma
s=s.replace("is fully deterministic.\n',", "is fully deterministic.\n\",")
# fix doubled apostrophes (R double-quoted string: single apostrophe is literal)
s=s.replace("stock''s","stock's").replace("portfolio''s","portfolio's").replace("test''s","test's")
# also the "investor''s"? none. fix any remaining ''
open(p,'w').write(s)
print("opening dquote:", s.count('sprintf(\n"# Research Memo:'))
print("remaining doubled apostrophes:", s.count("''"))
PY
grep -n 'sprintf(' analysis.R; grep -n 'is fully deterministic' analysis.Ropening dquote: 1 remaining doubled apostrophes: 0 541:memo <- sprintf( 666:is fully deterministic.
cd /app && sed -n '542,665p' analysis.R | grep -n '"' ; echo "--- stray % check (should only show %d %.Nf %%) ---" ; sed -n '542,665p' analysis.R | grep -oE '%[^ ]?' | sort | uniq -c
1:"# Research Memo: The Stock-Market Impact of Product-Recall Announcements in the Toy Industry
--- stray % check (should only show %d %.Nf %%) ---
4 %%
33 %.
6 %d
1 %scd /app && rm -f outputs/* && Rscript analysis.R 2>&1 | tail -3
Done. n_valid_events = 35 rho_bar = 0.0057 HAC L = 3 calendar n_days = 230 memo words = 1172
cd /app && ls -la outputs/ && echo "=== MEMO (first 60 lines) ===" && sed -n '1,60p' outputs/research_memo.md
total 160 drwxrws--- 2 h2tagent h2tagent 4096 Jun 20 18:04 . drwxrws--- 4 h2tagent h2tagent 4096 Jun 20 18:03 .. -rw-r--r-- 1 h2tagent h2tagent 51625 Jun 20 18:04 car_timeline.png -rw-r--r-- 1 h2tagent h2tagent 3618 Jun 20 18:04 event_cars.csv -rw-r--r-- 1 h2tagent h2tagent 1839 Jun 20 18:04 event_study_results.json -rw-r--r-- 1 h2tagent h2tagent 89350 Jun 20 18:04 portfolio_comparison.png -rw-r--r-- 1 h2tagent h2tagent 7926 Jun 20 18:04 research_memo.md === MEMO (first 60 lines) === # Research Memo: The Stock-Market Impact of Product-Recall Announcements in the Toy Industry ## Executive summary We study how the equity market reacts when toy manufacturers announce product recalls. Using a modern event-study design applied to 35 recall events across 18 firms (14 of the 18 firms in the sample experienced at least one recall), we find that recalls are associated with an economically large and statistically robust **negative** stock-price reaction concentrated in the days immediately surrounding the announcement. The average three-day (-1,+1) cumulative abnormal return is about **-2.92%**, and the announcement-day abnormal return alone averages **-1.31%**. The effect is pervasive rather than driven by a few outliers: 83% of events show a negative standardized cumulative abnormal return (SCAR) over the three-day window. In plain terms, a recall destroys a meaningful slice of shareholder value almost immediately, and the market appears to absorb the news quickly. ## 1. Magnitude and statistical significance of abnormal returns Abnormal returns measure the portion of a stock's move that cannot be explained by the overall market (via a firm-specific market model estimated over a 200-trading-day window ending 30 days before the event). Standardizing each event by its own prediction error makes events comparable. The mean three-day SCAR is **-1.012** (in standard-deviation units). The formal tests overwhelmingly reject the hypothesis of no reaction: the Patell z is **-5.98**, the Boehmer-Musumeci-Poulsen (BMP) t is **-4.99**, and the Kolari-Pynnonen (KP) cross-correlation-robust t is **-4.57** (two-sided p < 0.001). The tighter two-day (0,+1) window tells the same story (mean SCAR -0.862; BMP t -4.51), while the wider eleven-day (-5,+5) window is weaker but still significant (mean SCAR -0.451; BMP t -2.17). That the signal is strongest in the narrow windows and decays in the wide window indicates the information is incorporated rapidly, with little evidence of a continuing slide. Because the BMP and KP statistics (which allow for event-induced volatility and cross-event correlation, here rho-bar = 0.0057) remain large, the result is not an artifact of variance or clustering assumptions. The Schipper-Thompson joint Wald test that all three window means are simultaneously zero is decisively rejected (chi-square = 25.6 on 3 d.f., p < 0.001). ## 2. What drives the cross-sectional heterogeneity? Not all recalls are punished equally. Regressing the three-day SCAR on recall and firm characteristics (with heteroskedasticity- and autocorrelation-robust Newey-West standard errors, lag = 3) explains a substantial share of the variation (R-squared = 0.37). The economically and statistically important drivers are: * **Media coverage** (coefficient -0.140, t = -3.09): the more press articles a recall generates, the sharper the price decline. Media attention proxies for the salience and reputational reach of the event , investors react to how visible a recall is to consumers, not merely to its existence. * **Firm size** (log market cap, coefficient -0.350, t = -3.20): larger firms show larger standardized reactions. Big, well-known toy brands have more reputation and franchise value at stake, and their low idiosyncratic volatility means a given dollar shock registers as a larger standardized move. * **Scale of the recall** (log units recalled, coefficient -0.277, t = -1.93): bigger recalls are priced more negatively, consist …[truncated]
cd /app && sed -n '60,130p' outputs/research_memo.md
* **Clinical severity score** (coefficient -0.049, t = -0.62): strikingly, the hazard-severity rating is **not** a significant driver. The market appears to price the *breadth and visibility* of a recall (how many units, how much press, whose brand) more than an engineering assessment of how dangerous each unit is. The weighted-least-squares specification (weighting by inverse idiosyncratic variance) yields the same qualitative pattern, confirming the ranking of effects is not an artifact of noisy small-cap observations. ## 3. Calendar-time portfolio vs. the short-window results To check whether the short-window losses represent a tradable, persistent drift or a one-time repricing, we form a calendar-time portfolio (Jaffe-Mandelker / Fama 1998): on each of 230 trading days we hold an equally weighted basket of firms within 30 trading days of a recall and regress its return on the market. The portfolio's alpha is **-0.0009 per day** (roughly -21.6% annualized) with a t-statistic of only **-1.35** (p = 0.18) , not statistically significant. The market beta is 1.03. The contrast is instructive. The event study finds a sharp, highly significant drop *at* the announcement, yet the calendar-time alpha is statistically indistinguishable from zero. This is the hallmark of an **efficient, rapid repricing**: the loss is realized in the first day or two and is not recoverable by a strategy that buys recalling firms after the news. The discrepancy is a methodological lesson , long-horizon calendar-time tests have low power to detect events whose impact is concentrated in a few days, so the absence of a calendar-time alpha does not contradict the event-study finding; it confirms there is no predictable post-announcement drift to exploit. ## 4. Do the non-parametric tests corroborate the parametric ones? Parametric tests assume roughly normal abnormal returns. We therefore add two distribution-free checks. The **Corrado (1989) rank test**, which uses only the ordering of raw returns, gives z = **-2.43** (p = 0.015) , independently confirming a significant negative reaction and showing the result is not an artifact of a few extreme observations or fat tails. The **Cowan (1992) generalized sign test** compares the fraction of events with at least one positive abnormal return in the (-1,+1) window (0.51) against the benchmark positive-return frequency (p-bar = 0.49), yielding z = **0.25** (p = 0.80), which is not significant. The sign test's neutrality is itself informative: the recall effect operates through the *magnitude* of negative returns (large down-moves) rather than through a simple change in the direction of every single day. Taken together, the rank test corroborates the parametric conclusion while the sign test reminds us that the damage is about the size of the losses, not merely their frequency , i.e., abnormal returns are negatively skewed around recalls. ## 5. Practical conclusion for regulators and investors For a **regulator**, the evidence shows that capital markets impose a swift, sizeable penalty on toy makers that announce recalls, and that the penalty scales with the public visibility and scale of the event. Market discipline thus reinforces safety incentives, but because the market keys on *media salience and units* more than on the measured *hazard severity*, there is a policy case for standardized, prominent disclosure so that genuinely dangerous (if quiet) recalls are not under-penalized. For an **investor**, the practical takeaway is that the bad news is priced almost immediately: there is no reliable post-announcement drift to trade (the calendar-time alpha is insignificant), so strategies should focus on risk management and pre-event exposure rather than on reacting after the headline. Larger, higher-profile brands carry greater recall-related tail risk per unit of normal volatility, a consideration for position sizing and hedging in this industry. *Methodology note:* all statistics were comput …[truncated]
cd /app && python3 - <<'PY'
import json
d=json.load(open("/app/outputs/event_study_results.json"))
# expected schema
top_scalars={"n_events":int,"n_firms":int,"n_firms_with_recalls":int,"n_valid_events":int,"rho_bar":float}
for k,t in top_scalars.items():
assert k in d, f"missing {k}"
assert isinstance(d[k], t if t is float else int), f"{k} type {type(d[k])}"
win_keys={"mean_scar","patell_z","bmp_t","kp_t","pct_negative","n"}
for w in ["window_3day","window_2day","window_11day"]:
assert set(d["aggregate_scars"][w])==win_keys, (w, set(d["aggregate_scars"][w]))
assert isinstance(d["aggregate_scars"][w]["n"],int)
hac_keys={"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"}
assert set(d["cross_section_hac"])==hac_keys, set(d["cross_section_hac"])
assert isinstance(d["cross_section_hac"]["n_obs"],int) and isinstance(d["cross_section_hac"]["hac_lag"],int)
wls_keys=hac_keys-{"hac_lag"}
assert set(d["cross_section_wls"])==wls_keys, set(d["cross_section_wls"])
assert set(d["calendar_time"])=={"alpha","beta","t_alpha","p_value","n_days"}
assert isinstance(d["calendar_time"]["n_days"],int)
assert set(d["corrado_rank"])=={"z_stat","p_value"}
assert set(d["cowan_sign"])=={"z_stat","p_value","p_bar","frac_positive"}
assert set(d["schipper_thompson"])=={"wald_stat","wald_p","df"}
assert d["schipper_thompson"]["df"]==3
print("JSON schema OK. All keys present with correct types.")
print("Top-level keys:", list(d.keys()))
PYJSON schema OK. All keys present with correct types. Top-level 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']
cd /app && head -1 outputs/event_cars.csv && echo "---" && python3 -c "
import csv
r=list(csv.reader(open('/app/outputs/event_cars.csv')))
hdr=r[0]
exp=['event_id','firm_id','date','scar_3day','scar_2day','scar_11day','ar_day0']
print('header:',hdr)
print('matches required (order+names):', hdr==exp)
print('n data rows:', len(r)-1)
""event_id","firm_id","date","scar_3day","scar_2day","scar_11day","ar_day0" --- header: ['event_id', 'firm_id', 'date', 'scar_3day', 'scar_2day', 'scar_11day', 'ar_day0'] matches required (order+names): True n data rows: 35
cd /app && cp outputs/event_study_results.json /tmp/run1.json && cp outputs/event_cars.csv /tmp/run1.csv && cp outputs/research_memo.md /tmp/run1.md && rm -f outputs/* && Rscript analysis.R >/dev/null 2>&1 && echo "JSON diff:" && diff /tmp/run1.json outputs/event_study_results.json && echo "(identical)" && echo "CSV diff:" && diff /tmp/run1.csv outputs/event_cars.csv && echo "(identical)" && echo "MEMO diff:" && diff /tmp/run1.md outputs/research_memo.md && echo "(identical)"
JSON diff: (identical) CSV diff: (identical) MEMO diff: (identical)
cd /tmp && rm -rf rob && mkdir -p rob/data rob/outputs && cd rob && Rscript -e '
set.seed(1)
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)
# inject sentinels, NAs, duplicate rows
returns$return[5] <- -99.0
returns$return[10] <- -50
returns$market_return[20] <- NA
returns <- rbind(returns, returns[c(1,2,3),]) # dup rows
# add an event on a clearly non-trading day (Sunday far future)
recalls <- rbind(recalls, data.frame(event_id=99, firm_id="FIRM_001", date="2099-01-03",
hazard_type="burn", units_recalled=1000, media_articles=2, severity_score=3.0))
# add an early event (no room for estimation window): very first part of sample
recalls <- rbind(recalls, data.frame(event_id=98, firm_id="FIRM_002", date=returns$date[1],
hazard_type="burn", units_recalled=1000, media_articles=2, severity_score=3.0))
write.csv(returns, "data/stock_returns.csv", row.names=FALSE)
write.csv(recalls, "data/recalls.csv", row.names=FALSE)
write.csv(firms, "data/firms.csv", row.names=FALSE)
cat("perturbed data written; n recalls=", nrow(recalls), "\n")
'
# make a temp copy of the script pointing at temp dirs
sed 's#/app/data/#/tmp/rob/data/#g; s#/app/outputs#/tmp/rob/outputs#g' /app/analysis.R > /tmp/rob/analysis_rob.R
Rscript /tmp/rob/analysis_rob.R 2>&1 | tail -4
echo "--- outputs produced ---"; ls /tmp/rob/outputsperturbed data written; n recalls= 37 Done. n_valid_events = 36 rho_bar = 0.0056 HAC L = 3 calendar n_days = 291 memo words = 1175 --- outputs produced --- car_timeline.png event_cars.csv event_study_results.json portfolio_comparison.png research_memo.md
cd /tmp/rob && python3 -c "
import json
d=json.load(open('outputs/event_study_results.json'))
print('n_events:',d['n_events'],'n_valid_events:',d['n_valid_events'])
" && echo "--- which event_ids survived (98/99 are the injected ones) ---" && cut -d, -f1 outputs/event_cars.csv | tr -d '\"' | tail -n +2 | sort -n | tr '\n' ' ' && echo "" && Rscript -e '
r <- read.csv("/tmp/rob/data/stock_returns.csv"); r<-r[!is.na(r$return)&!is.na(r$market_return)&r$return>=-10,]; r<-r[!duplicated(r),]
ad<-sort(unique(as.Date(r$date)));
cat("idx of 2006-11-22 (event 98):", match(as.Date("2006-11-22"),ad)-1, "(needs >=230)\n")
cat("earliest date:", as.character(min(ad)), "\n")'n_events: 37 n_valid_events: 36 --- which event_ids survived (98/99 are the injected ones) --- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 98 idx of 2006-11-22 (event 98): 231 (needs >=230) earliest date: 2006-01-03
rm -rf /tmp/rob /tmp/run1.* && cd /app && rm -rf outputs && Rscript analysis.R 2>&1 | tail -2 && echo "--- final outputs ---" && ls -la outputs/
Done. n_valid_events = 35 rho_bar = 0.0057 HAC L = 3 calendar n_days = 230 memo words = 1172 --- final outputs --- total 160 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 51625 Jun 20 18:07 car_timeline.png -rw-r--r-- 1 h2tagent h2tagent 3618 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 89350 Jun 20 18:07 portfolio_comparison.png -rw-r--r-- 1 h2tagent h2tagent 7926 Jun 20 18:07 research_memo.md
cd /app && sed -n '75,170p' analysis.R
for (i in seq_len(n_events)) {
estr <- as.character(recalls$date[i])
if (!(estr %in% names(date_to_idx))) next
eidx <- as.integer(date_to_idx[estr])
emods[[i]] <- fit_market_model(recalls$firm_id[i], eidx)
}
event_rows <- list()
for (i in seq_len(n_events)) {
fid <- recalls$firm_id[i]
estr <- as.character(recalls$date[i])
if (!(estr %in% names(date_to_idx))) next
eidx <- as.integer(date_to_idx[estr])
m <- emods[[i]]
if (is.null(m)) next
fp <- firm_panel[[fid]]
scars <- list(); raw_cars <- list(); ar_day0 <- NA_real_; valid_w3 <- TRUE
for (wname in names(windows)) {
w <- windows[[wname]]; ars <- numeric(0); factsum <- 0; ok <- TRUE
for (off in seq.int(w[1], w[2])) {
tidx <- eidx + off
if (tidx < 0 || tidx >= n_all) { ok <- FALSE; break }
target <- as.character(all_dates[tidx + 1])
if (!(target %in% rownames(fp))) { ok <- FALSE; break }
rm_t <- fp[target, "market_return"]
ret_t <- fp[target, "return"]
ar <- ret_t - (m$alpha + m$beta * rm_t)
ars <- c(ars, ar)
# Patell prediction-error variance factor for this day
factsum <- factsum + 1 + 1 / m$n_est + (rm_t - m$mean_rm)^2 / m$ss_rm
if (wname == "w3" && off == 0) ar_day0 <- ar
}
if (!ok) {
if (wname == "w3") valid_w3 <- FALSE
scars[[wname]] <- NA_real_; raw_cars[[wname]] <- NA_real_
} else {
car <- sum(ars)
s_car <- m$S * sqrt(factsum) # prediction-error-corrected SD
scars[[wname]] <- car / s_car # standardized CAR
raw_cars[[wname]] <- car # raw cumulative abnormal return
}
}
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,
scar_3day = scars$w3,
scar_2day = scars$w2,
scar_11day = scars$w11,
ar_day0 = ar_day0,
rawcar_3 = raw_cars$w3,
rawcar_2 = raw_cars$w2,
rawcar_11 = raw_cars$w11,
eidx = eidx,
alpha_hat = m$alpha,
beta_hat = m$beta,
n_est = m$n_est,
stringsAsFactors = FALSE
)
}
event_df <- do.call(rbind, event_rows)
event_df <- event_df[order(event_df$event_id), ]
rownames(event_df) <- NULL
n_valid_events <- nrow(event_df)
# =====================================================================
# 3. rho_bar : mean pairwise correlation of per-firm panel residuals
# (single OLS of return ~ market_return on each firm's full panel)
# =====================================================================
resid_by_firm <- list()
for (f in names(firm_panel)) {
fp <- firm_panel[[f]]
if (nrow(fp) < 30) next # drop short panels
mm <- lm(return ~ market_return, data = fp)
resid_by_firm[[f]] <- setNames(as.numeric(resid(mm)), as.character(fp$date))
}
rho_vals <- numeric(0)
rf_names <- names(resid_by_firm)
if (length(rf_names) >= 2) {
for (a in 1:(length(rf_names) - 1)) {
for (b in (a + 1):length(rf_names)) {
ra <- resid_by_firm[[rf_names[a]]]
rb <- resid_by_firm[[rf_names[b]]]
common <- intersect(names(ra), names(rb))
if (length(common) < 20) next # need >= 20 overlapping obs
rho_vals <- c(rho_vals, cor(ra[common], rb[common]))
}
}
}
rho_bar <- if (length(rho_vals) > 0) mean(rho_vals) else 0.0cd /app && echo "=== MEMO word count ===" && wc -w outputs/research_memo.md && echo "" && echo "=== Required theme coverage ===" && for kw in "significan" "severity" "media" "firm size" "calendar-time" "Corrado" "Cowan" "regulator" "investor" "predictab"; do printf "%-16s: %s\n" "$kw" "$(grep -ci "$kw" outputs/research_memo.md) hits"; done && echo "" && echo "=== FINAL JSON ===" && cat outputs/event_study_results.json
=== MEMO word count ===
1172 outputs/research_memo.md
=== Required theme coverage ===
significan : 9 hits
severity : 3 hits
media : 7 hits
firm size : 1 hits
calendar-time : 7 hits
Corrado : 2 hits
Cowan : 2 hits
regulator : 2 hits
investor : 3 hits
predictab : 1 hits
=== FINAL 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
}
}No file changes, the agent left the workspace untouched.
# SyncVals normalized verifier summary
# task: product-recall-stock-price-event
# attempt: 6 status: completed raw_score: 0.0
# reward rule: binary: score 0.0 != 1.0
# => reward = 0.0 (FAIL)
#
# 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).
----------------------------------------------------------------------
=== MEMO word count ===
1172 outputs/research_memo.md
=== Required theme coverage ===
significan : 9 hits
severity : 3 hits
media : 7 hits
firm size : 1 hits
calendar-time : 7 hits
Corrado : 2 hits
Cowan : 2 hits
regulator : 2 hits
investor : 3 hits
predictab : 1 hits
=== FINAL 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
}
}Reproduce this trial: git checkout 2f94510 && PYTHONPATH=src python3 scripts/build_site.py , then open trial/trial_00819674e3ab42e2. Re-running the agent live requires EVAL_PLATFORM_ENABLE_OAUTH_SMOKE=1 and is non-deterministic.
Trial trial_00819674e3ab42e2 · verifier authoritative; classifier explanatory.