Exercise · m12_event_study.py
Event studies (MacKinlay 1997; Patell 1976; Boehmer-Musumeci-Poulsen 1991)
not run yet
Not saved: sign up to keep your code"""M12 exercise: event studies (MacKinlay 1997; Patell 1976; Boehmer-Musumeci-Poulsen 1991).
Read notes.md §12.1–12.3 first. Run:
cd exercises && .venv/bin/python -m pytest modules/M12-geopolitics-events/tests/test_m12_event_study.py
Index conventions
* Returns are 1-d arrays (one asset) or 2-d arrays of shape (T, N) (N assets,
one column each), all aligned with a market return array r_m of length T.
* event_idx is the integer row of event day 0 ("tau = 0").
* Windows are inclusive offsets relative to event_idx:
est = (-250, -11) means rows event_idx-250 .. event_idx-11 (L1 = 240 days)
win = (-1, 1) means rows event_idx-1 .. event_idx+1 (L2 = 3 days)
Vectorise over firms: the tests run thousands of firms at once.
"""
from __future__ import annotations
import numpy as np
def market_model_fit(r_i: np.ndarray, r_m: np.ndarray) -> dict:
"""OLS market model R_it = alpha_i + beta_i R_mt + eps_it on the estimation window
(eq. 12.1). r_i is (L1,) or (L1, N); r_m is (L1,).
Return {"alpha", "beta", "sigma2", "L1", "xtx_inv"} where
alpha, beta: scalars or (N,) arrays,
sigma2 = RSS/(L1 - 2) per asset (eq. 12.3),
xtx_inv = (X'X)^{-1} for X = [1, r_m] (2x2)."""
raise NotImplementedError
def abnormal_returns(r_i: np.ndarray, r_m: np.ndarray, alpha, beta) -> np.ndarray:
"""AR_t = R_it - alpha - beta R_mt (eq. 12.4). Broadcast over columns when r_i is 2-d."""
raise NotImplementedError
def ar_covariance_factor(fit: dict, r_m_event: np.ndarray) -> np.ndarray:
"""Return the (L2 x L2) matrix M = I + X*(X'X)^{-1}X*' with X* = [1, r_m_event],
so that Var(AR* | X) = sigma^2 M (eq. 12.5)."""
raise NotImplementedError
def car_variance(fit: dict, r_m_event: np.ndarray):
"""Var(CAR) = sigma2 * 1'M1 (eq. 12.8). Scalar or (N,) array."""
raise NotImplementedError
def event_study(
r_i: np.ndarray,
r_m: np.ndarray,
event_idx: int,
est: tuple[int, int] = (-250, -11),
win: tuple[int, int] = (-1, 1),
) -> dict:
"""Market-model event study for one asset or N assets.
Raise ValueError if a window falls outside the data or if est[1] >= win[0]
(the estimation window must end before the event window starts).
Return dict with keys
"alpha", "beta", "sigma2", "L1", "L2",
"ar" : abnormal returns over the event window, (L2,) or (L2, N)
"car" : sum of ar over the window, scalar or (N,)
"var_car" : eq. (12.8)
"scar" : car / sqrt(var_car) (Proposition 12.2: t with L1-2 df under H0)"""
raise NotImplementedError
def j1_test(car: np.ndarray, var_car: np.ndarray) -> float:
"""J1 = mean(CAR) / sqrt(sum_i var_car_i / N^2) (eq. 12.10)."""
raise NotImplementedError
def patell_z(scar: np.ndarray, L1: int) -> float:
"""Z = sum_i SCAR_i / sqrt(N (L1-2)/(L1-4)) (eq. 12.12)."""
raise NotImplementedError
def bmp_t(scar: np.ndarray) -> float:
"""BMP t = mean(SCAR) / (sd(SCAR, ddof=1)/sqrt(N)) (eq. 12.13)."""
raise NotImplementedError
def cross_sectional_t(car: np.ndarray) -> float:
"""t = mean(CAR) / (sd(CAR, ddof=1)/sqrt(N)) (eq. 12.11)."""
raise NotImplementedError
def simulate_event_panel(
r_m: np.ndarray,
n_firms: int,
event_idx: int,
abnormal: float = 0.0,
sigma: float = 0.015,
var_mult: float = 1.0,
var_window: tuple[int, int] = (0, 0),
seed: int = 0,
) -> np.ndarray:
"""Simulate R_it = a_i + b_i R_mt + eps_it, shape (T, n_firms), with
rng = np.random.default_rng(seed) drawing, in this order:
a = rng.normal(0, 0.0003, n_firms)
b = rng.uniform(0.5, 1.5, n_firms)
eps = sigma * rng.standard_normal((T, n_firms))
Multiply eps on rows event_idx+var_window[0] .. event_idx+var_window[1]
(inclusive) by sqrt(var_mult). Add `abnormal` to every firm on row event_idx."""
raise NotImplementedError
No runs yet
The stub's functions raise
NotImplementedError until you write them. Fill in one, press
Run tests, and watch its tests turn green.Reference solution
Available after your first run, with an account approved for code runs.