13  Event studies

In previous chapters, we studied papers examined the reaction of financial markets to information. Chapter 10 covered Fama et al. (1969), which studied the adjustment of prices to the information in stock splits. Chapter 11 examined Ball and Brown (1968), which shows that market returns over a year are correlated with earnings news for the period. Chapter 12 studied Beaver (1968), which shows that volume and price volatility increase around earnings announcements.

The decades since those early papers have seen significant evolution in how researchers study the market reaction to information and this chapter provides an introduction to current event-study methods.

Tip

The code in this chapter uses the packages listed below. For instructions on how to set up your computer to use this code, go to the support page for this book. The support page also includes Quarto templates for the code and exercises below.

import polars as pl
import statsmodels.formula.api as smf
from scipy.stats import norm
from maketables import ETable
from era_pl import (load_data, load_parquet,
                    get_trading_dates, get_event_dates)
from plotnine_polars import aes

13.1 Overview

MacKinlay (1997, p. 13) defines an event study as one that, “using financial market data … measures the impact of a specific event on the value of a firm. The usefulness of such a study comes from the fact that, assuming highly efficient markets, the effects of an event will be reflected immediately in security prices.1 Thus a measure of the event’s economic impact can be constructed using security prices observed over a relatively short time period.”

MacKinlay (1997, p. 14) continues: “In the late 1960s seminal studies by Ray Ball and Philip Brown (1968) and Eugene Fama et al. (1969) introduced the methodology that is essentially the same as that which is in use today. Ball and Brown considered the information content of earnings, and Fama et al. studied the effects of stock splits after removing the effects of simultaneous dividend increases.”

Event studies examine the impact of a class of identifiable events on one or more variables of economic interest. In capital markets research, the variable of economic interest is typically the returns of a firm’s shares around the event.

The basic ingredients of an event study are:

  • A class of events: earnings announcements, merger announcements, stock splits, earnings forecast changes. In many research papers, these events represent the treatment of interest.
  • An outcome variable of interest: accounting policy, market returns, trading volume.
  • Control observations: observations for which the event did not occur.
  • Control variables: additional variables that may be correlated with both the event—such as dividend announcements with earnings announcements or forecast revisions with earnings announcements—and also returns (see Chapter 4 for more on control variables).

Additionally, as we saw in Chapter 12, lining up observations in event time is a critical feature of most event studies.

13.1.1 Discussion questions

  1. Does Ball and Brown (1968) meet the MacKinlay (1997) definition of an event study? What features are present and what, if any, are missing?

  2. Does Beaver (1968) meet the MacKinlay (1997) definition of an event study? What features are present and what, if any, are missing?

13.2 The modern event study

The event study has evolved over time. While event studies today generally meet the definition in MacKinlay (1997), the event-study approach has changed as it has been adapted to a wider variety of situations.

One change is that researchers have become more interested in using event studies to understand the economic effects of regulation, rather than the market reaction to firm-specific announcements. Fama et al. (1969) studied stock-splits and Beaver (1968) studied earnings announcements. In each case, the events are firm-level events that are largely independent of each other (e.g., they are not excessively clustered in time). In contrast, each of the three more recent event studies we study below uses regulatory events such as events affecting the probability of legislation (Larcker et al., 2011; Zhang, 2007) or accounting standards going into effect (Khan et al., 2017).

A related change is an increased reliance on market efficiency, as the typical modern event study uses (in the words of MacKinlay, 1997) “security prices observed over a relatively short time period” as a “measure of the event’s economic impact”. Neither Fama et al. (1969) nor Beaver (1968) relies heavily on market efficiency in establishing that markets appear to react to stock-splits and earnings announcements, respectively, and neither study seeks to show whether stock-splits or earnings announcements create (or destroy) value. In contrast, the modern event study is often leaning on market efficiency to evaluate regulation. For example, using an event study to ask “do the FASB’s standards add shareholder value?” (Khan et al., 2017) relies heavily on the market having an informed view of the kind implied by stronger forms of market efficiency.

A consequence of this changed emphasis is that often there are fewer independent observations for the researcher to work with. For example, the primary analysis of Zhang (2007) focuses on four event windows, far fewer than the 506 earnings announcements in Beaver (1968). As we will see, researchers often use supplementary analyses to address the relative paucity of data.

13.2.1 A small event study

To better understand the modern event study, we conduct a mini-study of our own. Suppose that we want to understand better the value-creation process at Apple with a particular emphasis on Apple’s product development process. At the time of writing (mid-2022), Apple is the most valuable company in the world, with a market capitalization over US$2 trillion; so understanding how it creates value for shareholders may be of interest to researchers.

As Apple is notoriously secretive about its product pipeline, the media events at which its products are launched are closely watched affairs. For example, at the Macworld Conference & Expo San Francisco 2007 (9 January 2007), Apple announced the iPhone, which would go on to become Apple’s primary revenue source and one of the largest phone products in the world. At an Apple Special Event on 27 January 2010, Apple announced the iPad, Apple’s tablet computer.

So, to understand whether Apple’s products create value for Apple shareholders, we might run an event study using Apple’s media events as the events of interest.

The era_pl package includes the data set apple_events, which is derived from data found on Wikipedia. Let’s look at the last few rows of this table:

apple_events = load_data("apple_events")
apple_events.tail()
shape: (5, 3)
event event_date end_event_date
str date date
"Apple Special Event" 2019-12-02 2019-12-02
"WWDC 2020" 2020-06-22 2020-06-26
"Apple Special Event" 2020-09-15 2020-09-15
"Apple Special Event" 2020-10-13 2020-10-13
"Apple Special Event" 2020-11-10 2020-11-10

We will need return data from CRSP to conduct our event study. We first need to get Apple’s PERMNO so we can look up returns on CRSP. Knowing that Apple’s ticker is AAPL helps.

stocknames = load_parquet("stocknames", "crsp")
dsf = load_parquet("dsf", "crsp")
dsi = load_parquet("dsi", "crsp")
idx_daily = load_parquet("idx_daily", "comp")
apple_permno = (
    stocknames
    .filter(pl.col("ticker") == "AAPL")
    .select("permno")
    .unique()
    .collect()
    .item()
)

We then use Apple’s PERMNO (apple_permno equals 14593) to get return data from CRSP. In this case, we will get daily returns for Apple (ret) from crsp.dsf and value-weighted “market” returns (vwretd) from crsp.dsi and calculate market-adjusted returns as ret - vwretd.2 In this case, we will grab all returns since the start of 2005, which covers all the events on apple_events.

apple_rets = (
    dsf
    .join(dsi.select("date", "vwretd"), 
          on="date", how="inner")
    .filter(
        pl.col("permno") == apple_permno,
        pl.col("date") >= pl.date(2005, 1, 1)
    )
    .with_columns(ret_mkt=pl.col("ret") - pl.col("vwretd"))
    .select("permno", "date", "ret", "ret_mkt", "vol")
)

Unlike the earnings announcements that we studied in Chapter 12, Apple’s media events extend over multiple days; so our event windows also need to extend over multiple days. To allow for some leakage of information in the day before the start of the media events and to allow the market some time to process the value implications of the media event, we will set our event window from one trading day before the start of each media event through to one day after the end of the media event. We create event windows by combining event dates with CRSP trading dates using the same approach as in Chapter 12.

apple_events = (
    load_data("apple_events")
    .lazy()
    .with_columns(
        permno=pl.lit(apple_permno),
    )
)
trading_dates = get_trading_dates(dsi)

apple_event_dates = get_event_dates(
    data=apple_events,
    permno="permno",
    event_date="event_date",
    end_event_date="end_event_date",
    win_start=-1,
    win_end=1,
)

We now organize the data in a way that allows us to depict Apple’s returns graphically over time including information about media events.

event_calendar = (
    trading_dates
    .join(
        apple_event_dates.select("permno", "start_td", "end_td"),
        how="cross",
    )
    .filter(pl.col("td").is_between(pl.col("start_td"), pl.col("end_td")))
    .select("permno", "date")
    .unique()
    .with_columns(is_event=True)
)

apple_data = (
    apple_rets
    .join(event_calendar,
          on=["permno", "date"], how="left",
    )
    .with_columns(pl.col("is_event").fill_null(False))
    .select("permno", "date", "ret", "ret_mkt", "vol", "is_event")
)

Now we have the data we need, we can calculate cumulative returns using the cum_prod() method and then plot these returns over time.3

plot_df = (
    apple_data
    .sort("date")
    .with_columns(
        cumret=(1 + pl.col("ret").fill_null(0)).cum_prod(),
        switch=(
            pl.col("is_event") != pl.col("is_event").shift(-1)
        ).fill_null(False),
    )
    .with_columns(
        y_non_event=pl.when((~pl.col("is_event")) | pl.col("switch"))
                    .then(pl.col("cumret")),
        y_event=pl.when(pl.col("is_event") | pl.col("switch"))
                .then(pl.col("cumret")),
    )
    .collect()
)

(
    plot_df
    .ggplot(aes(x="date", y="cumret"))
    .geom_line()
    .geom_ribbon(aes(ymax="y_non_event", ymin=0, fill='"Non-event"'))
    .geom_ribbon(aes(ymax="y_event", ymin=0, fill='"Event"'))
    .add_theme(legend_position="bottom")
)
Plot of cumulative returns for Apple stock from 2005 to early 2020. While periods involving Apple media events are distinguished by colour from other periods, these are not visible in the plot at this scale. Cumulative returns are generally positive and reach an index value of 200 at the end of this period.
Figure 13.1: Apple returns

The line in Figure 13.1 represents cumulative returns since the start of the window. Two “ribbon” plots are added to this line: one for the non-event windows and one for the event windows. The vast majority of dates are non-event dates, making the event windows difficult to discern in the plot. But “zooming in” makes the event windows easier to discern, as seen in Figure 13.2, which focuses on the last quarter of 2020.

(
    plot_df
    .filter(pl.col("date").is_between(pl.date(2020, 9, 1),
                                      pl.date(2020, 12, 31)))
    .ggplot(aes(x="date", y="cumret"))
    .geom_line()
    .geom_ribbon(aes(ymax="y_non_event", ymin=0, fill='"Non-event"'))
    .geom_ribbon(aes(ymax="y_event", ymin=0, fill='"Event"'))
    .add_theme(legend_position="bottom")
)
Plot of cumulative returns for Apple stock from September 2020 to December 2020. Periods involving Apple media events are distinguished by colour from other periods, and these are more clearly visible in this plot due to the change in scale from the previous plot. Cumulative returns are generally flat during this period.
Figure 13.2: Apple returns: “Zoomed in”

There is little in the plots above to suggest that Apple media events are associated with unusual returns, but we will use regression analysis to test this more formally. We consider whether returns are different when the indicator variable is_event is true. Inspired by Beaver (1968) (see Chapter 12), we also consider the absolute value of returns (similar to squared return residuals used in Beaver, 1968) and relative trading volume.

def ols_fit(formula, data):
    data = data.with_columns(pl.col("is_event").cast(pl.Int32))
    return smf.ols(formula, data=data.to_pandas()).fit()

fms = [ols_fit(formula, plot_df) 
       for formula in 
            ["ret_mkt ~ is_event",  
             "I(abs(ret)) ~ is_event", 
             "I(vol / vol.mean()) ~ is_event"]
    ]
ETable(fms,
       model_heads=["ret_mkt", "abs(ret)", "Volume"],
       head_order="h"
)
Table 13.1: Regression analysis of Apple media events
ret_mkt abs(ret) Volume
(1) (2) (3)
coef
is_event -0.002**
(0.001)
0.001
(0.001)
0.036
(0.054)
Intercept 0.001***
(0.000)
0.014***
(0.000)
0.999***
(0.011)
stats
Observations 5,033 5,033 5,033
R2 0.000886 0.000214 0.000089
Significance levels: * p < 0.1, ** p < 0.05, *** p < 0.01. Format of coefficient cell: Coefficient (Std. Error)

Results from these regressions are reported in Table 13.1. These results—interpreted fairly casually—provide evidence of lower returns, but not higher (or lower) levels of either trading volume or return volatility.

The code above examines whether returns for Apple during event periods behave differently from returns during non-event periods. We can also calculate cumulative returns around each Apple event directly from our Polars data.

apple_rets_td = apple_rets.join(trading_dates, on="date", how="inner")

rets_apple = (
    apple_event_dates
    .join(apple_rets_td, 
          on="permno", how="inner")
    .filter(pl.col("td").is_between(pl.col("start_td"), 
                                    pl.col("end_td")))
    .group_by("event_date")
    .agg(pl.col("ret", "ret_mkt").sum())
    .sort("event_date")
    .collect()
)

We first look at market-adjusted returns, which on average barely differ from zero.

rets_apple.select("ret_mkt").mean().item()
-0.006071829787234042

How many media events are positive-return events? (Answer: Fewer than half!)

rets_apple.select((pl.col("ret_mkt") > 0).mean()).item()
0.44680851063829785

Finally, Figure 13.3 depicts market-adjusted returns for Apple media events by event date.

(
    rets_apple
    .ggplot(aes(x="event_date", y="ret_mkt"))
    .geom_point()
    .geom_hline(yintercept=rets_apple["ret_mkt"].mean())
)
Plot of market-adjusted returns for Apple media events against the dates of those events. The mean of these returns is depicted as a horizontal line that is just below the x-axis.
Figure 13.3: Apple market-adjusted returns and media events

13.2.2 Exercises

  1. How would you expect the plot to change if we used cumret = (pl.col("ret").fill_null(0) + 1).log().cum_sum().exp() in place of cumret = (1 + pl.col("ret").fill_null(0)).cum_prod() in creating the plot above? Is there any reason to prefer one calculation over the other?

  2. Do we get different results in this case if we use cumret = (1 + pl.col("ret")).cum_prod() (i.e., remove the fill_null(0) step)? If so, why? If not, would we always expect this to be the case (e.g., for stocks other than Apple)?

13.3 Event studies and regulation

Zhang (2007, p. 74) “investigates the economic consequences of the Sarbanes–Oxley Act (SOX) by examining market reactions to related legislative events.” Zhang (2007, p. 75) finds that “the cumulative value-weighted (equal-weighted) raw return of the U.S. market amounts to –15.35% (–12.53%) around the key SOX events.” As Zhang (2007) uses CRSP returns for the US market, we collect a local copy of the relevant data.

Zhang (2007, p. 76) focuses some analyses on “key SOX events” (defined below) and finds that “the estimated U.S. cumulative abnormal returns range from –3.76% and –8.21% under alternative specifications and are all statistically significant.” Here “all” means for each of value-weighted and equal-weighted returns and using abnormal returns relative to each of the two models. For convenience, we focus on the model that measures abnormal returns relative to a “market model”, where the market comprises Canadian stocks not listed in the United States, and omit analysis of the second model, which blends returns on several non-US portfolios as a benchmark. To this end, we collect data on returns for the Toronto composite index (gvkeyx == "000193") from Compustat’s index data (comp.idx_daily) over 2001 and 2002 and merge this data set with our local copy of crsp.dsi.

can_rets = (
    idx_daily
    .filter(pl.col("gvkeyx") == "000193")
    .sort("datadate")
    .with_columns(
        prev_prccd=pl.col("prccd").shift(1),
    )
    .with_columns(
        ret_can=pl.col("prccd")
                .era.div_if_pos("prev_prccd") - 1
    )
    .filter(
        pl.col("datadate").is_between(
            pl.date(2000, 1, 1),
            pl.date(2002, 12, 31),
        )
    )
    .select(pl.col("datadate").alias("date"),
            "ret_can")
)

We follow Zhang (2007, p. 88) in “using daily return data in the 100 days prior to December 28, 2001” for expected return models.

reg_data = (
    dsi
    .select("date", "vwretd", "ewretd")
    .join(can_rets, on="date", how="inner")
    .filter(pl.col("date") < pl.date(2001, 12, 28))
    .sort("date", descending=True)
    .limit(100)
    .collect()
)

We then fit models for market returns for both equal-weighted and value-weighted portfolios against Canadian returns.

fm_vw = smf.ols("vwretd ~ ret_can", data=reg_data.to_pandas()).fit()
fm_ew = smf.ols("ewretd ~ ret_can", data=reg_data.to_pandas()).fit()

We then use these models to calculate excess returns for all observations. The .predict() method requires a pandas data frame.

dsi_merged = (
    dsi
    .select("date", "vwretd", "ewretd")
    .join(can_rets, on="date", how="inner")
    .collect()
    .pipe(
        lambda df: df.with_columns(
            pl.Series("fit_vw", fm_vw.predict(df.to_pandas())),
            pl.Series("fit_ew", fm_ew.predict(df.to_pandas())),
        )
    )
    .with_columns(
        abret_vw=pl.col("vwretd") - pl.col("fit_vw"),
        abret_ew=pl.col("ewretd") - pl.col("fit_ew"),
    )
    .drop("ret_can", "fit_vw", "fit_ew")
)

From Table 2, Zhang (2007) appears to calculate the daily standard deviation of returns at about 1.2%. The exact basis for this calculation is unclear, but similar analyses are “estimated using daily return data in the 100 days prior to December 28, 2001” (Zhang, 2007, p. 88).

sd_ret = (
    dsi
    .filter(pl.col("date") < pl.date(2001, 12, 28))
    .sort("date", descending=True)
    .limit(100)
    .select(pl.col("vwretd").std())
    .collect()
    .item()
)

So we calculate the daily volatility on this basis using the calculation above, which yields the value 1.280%.

The era_pl package contains the data set zhang_2007_windows, which contains the dates of the event windows found in Table 2 of Zhang (2007). We can combine these data with return data from dsi_merged to calculate cumulative returns for each event window. Following Zhang (2007), we can estimate the standard error by scaling the daily return volatility by the square-root of the number of trading days in each window to calculate a t-statistic for each event. We use the standard deviation of residuals to estimate the daily volatility of the abnormal-return models.

zhang_2007_windows = load_data("zhang_2007_windows")

zhang_2007_rets = (
    zhang_2007_windows
    .join(
        dsi_merged,
        how="cross",
    )
    .filter(
        pl.col("date").is_between(pl.col("beg_date"),
                                  pl.col("end_date"))
    )
    .group_by("event")
    .agg(
        pl.col("date").count().alias("n_days"),
        pl.col("vwretd", "ewretd", 
               "abret_vw", "abret_ew").sum(),
    )
    .with_columns(sqrt_n=pl.col("n_days").sqrt())
    .with_columns(
        vw_t=pl.col("vwretd") / 
                (pl.col("sqrt_n") * sd_ret),
        ew_t=pl.col("ewretd") / 
                (pl.col("sqrt_n") * sd_ret),
        abret_vw_t=pl.col("abret_vw") / 
                        (pl.col("sqrt_n") * fm_vw.resid.std()),
        abret_ew_t=pl.col("abret_ew") / 
                        (pl.col("sqrt_n") * fm_ew.resid.std()),
    )
)

In subsequent analyses, Zhang (2007) focuses on “key SOX events”, which seem to be those events with a “statistically significant” return at the 10% level in a two-tailed test, and reports results in Panel D of Table 1 (2007, pp. 91–92). We replicate the key elements of this procedure and our results correspond roughly with those reported in Zhang (2007) as “CAR2”.

zhang_2007_res = (
    zhang_2007_rets
    .filter(pl.col("vw_t").abs() > abs(norm.ppf(0.05)))
    .select("n_days", "vwretd", "ewretd", "abret_vw", "abret_ew")
    .sum()
    .with_columns(sqrt_n=pl.col("n_days").sqrt())
    .with_columns(
        vw_t=pl.col("vwretd") / 
                (pl.col("sqrt_n") * sd_ret),
        ew_t=pl.col("ewretd") / 
                (pl.col("sqrt_n") * sd_ret),
        abret_vw_t=pl.col("abret_vw") /
                (pl.col("sqrt_n") * fm_vw.resid.std()),
        abret_ew_t=pl.col("abret_ew") /
                (pl.col("sqrt_n") * fm_ew.resid.std())
    )
)

We estimate cumulative raw value-weighted returns for the four “key SOX events” at -15.21% (t-statistic -3.18), quite close to the value reported in Zhang (2007) (-15.35% with a t-statistic of -3.49). However, our estimate of cumulative abnormal value-weighted returns for the four “key SOX events” is -3.18% (t-statistic -1.02), which is closer to zero than the value reported in Zhang (2007) (-8.21% with a t-statistic of -2.99), which is the only value of eight reported in Panel D of Table 1 that is statistically significant at conventional levels (5% in two-tailed tests).

13.3.1 Discussion questions

13.3.1.1 Zhang (2007)

  1. What are the relative merits of raw and abnormal returns in evaluating the effect of SOX on market values of US firms? What do you observe in the raw returns for Canada, Europe, and Asia for the four events that are the focus of Panel B of Table 2 of Zhang (2007)? Does this raise concerns about the results of Zhang (2007)?

  2. Describe the process for constructing the test statistics reported in Panel D of Table 2. How compelling are these results? Do you agree with the assessment by Leuz (2007, p. 150) that Zhang (2007) is “very careful in assessing the significance of the event returns”?

  3. Describe in detail how you might conduct statistical inference using randomization inference in the setting of Zhang (2007) (see Section 19.7 for more on this approach)? What are the challenges faced and design choices you need to make in applying this approach? Does your approach differ from the bootstrapping approach used in Zhang (2007)?

  4. Leuz (2007) identifies studies other than Zhang (2007) that find evidence that SOX was beneficial to firms? How can these sets of results be reconciled? What steps would you look to undertake to evaluate the conflicting claims of the two papers?

13.3.1.2 Khan et al. (2017)

  1. What is the research question examined in Khan et al. (2017)? (Hint: Read the title.)

  2. Khan et al. (2017, p. 210) argue that “an ideal research design to evaluate the benefits of accounting standards is to compare a voluntary disclosure regime, in which firms disclose information required by a particular standard, with a mandatory disclosure regime, in which firms are required to disclose that same information.” Do you agree that this research design would be “ideal” to address the question? What is the implied treatment in this ideal design?

  3. Compare the Apple event study above with Khan et al. (2017). What are the relative strengths and weaknesses of the two studies? Do you think an event-study approach is appropriate for addressing the question “do Apple products add value?” Do you think an event-study approach is appropriate for addressing the research question of Khan et al. (2017)? Why or why not?

  4. Do you think that standard-setters would view “reduction in estimation risk” as a goal of accounting standards? Evaluate the quality of the arguments linking improved standards to reduced estimation risk. The null hypothesis for Panel A is that the CAR of affected firms is not different from CAR of unaffected firms. How appropriate is it to report “most negative” and “most positive” CAR differences only? (Hint: If the null hypothesis is true, how many standards might you expect to have “statistically significant” coefficients?)

  5. Interpret the results of Table 5, Panel B of Khan et al. (2017).

13.3.1.3 Larcker et al. (2011) “LOT”

  1. How do LOT and FFJR differ in terms of the role of market efficiency in their research designs?

  2. Consider Table 1 of LOT. What are the differences between the event study design in LOT from that in FFJR? What are implications of these differences?

  3. How do you think Table 1 was developed? Do you see potential problems in the process underlying Table 1? Can you suggest alternative approaches to developing Table 1?

  4. Consider proxy access, as some of the core results of the paper relate to proxy access. If you were a shareholder in a company, what concerns might you have about proxy access? Why might this decrease the value of your shares? Think about this is concrete terms; be specific about the kinds of circumstances where value will be reduced. How well do the variables NLargeBlock and NSmallCoalitions measure the exposure of firms to the issues you identified in the previous question? (As part of this, consider the timing of variable measurement relative to the timing of possible value-reducing outcomes.)

  5. LOT makes use of a number of Monte Carlo simulations. How do these compare with the bootstrapping analyses conducted by Zhang (2007)? Are the simulations addressing the same underlying issues as Zhang (2007) bootstrapping approach?


  1. In terms of Section 10.1, it’s the ”price is right” notion of market efficiency that applies here.↩︎

  2. MacKinlay (1997, p. 18) points out that “the market-adjusted return model can be viewed as a restricted market model with \(\alpha_i\) constrained to be zero and \(\beta_i\) constrained to be one.”↩︎

  3. The purpose of the variable switch is to “fill” gaps in the plot that would arise in its absence. To see what this variable is doing, replace switch=(pl.col("is_event") != pl.col("is_event").shift(-1)).fill_null(False) with switch=pl.lit(False). These gaps are more apparent in Figure 13.2 than they are in Figure 13.1.↩︎