A Quick Explanation of Single Firm Event Studies
By: Peter Oliver Caya
Tags: Finance, Data Science, Statistics, R

Economists attempting to discern the way that some events impact a the value of a company’s stocks or bonds must find a way to measure how abnormal a change in the security’s value is. Often, these events can be something extraordinary (instances of fraud for example) but these impacts may involve something much more mundane such as the effect of stock splits on a company’s value. From here, cue a discussion on financial news networks like CNBC about the way that the news impacts the value of the company and the way that the company behaves as a result of the disclosure.

One way to determine the degree to which returns for a security are abnormal is to construct a model of the way that security typically behaves and then compare those predicted results to what actually happened. This methodology is referred to as an event study and has been used for decades in academia and industry. For example, the realm of legal cases for securities fraud deals with whether real harm was caused and what damages are. Academics have also used event study on multiple firms to understand how one specific type of event (like stock splits) impacts a collection of companies. My goal in this little article is to describe the underpinnings of event studies, and to show the basic steps in starting a single firm event study with a real example.

Before we try to determine whether something unusual has happened with stocks or bonds though, let’s try to use some basic principles to see if we can spot something unusual in the more simple context of coin-flipping.

Which Coins are Fair?

To determine what unusual impact an event has, we first have to come to some kind of understanding of what is normal. Let’s say that we have 1000 coins and that we want to determine which of the coins is fair and which are unfair. One possible way to accomplish our objective would be to flip each coin 100 times to see if the number of heads and tails falls within an acceptable distance from our expectation (50–50).

To determine what is acceptable, we have to pose a probability distribution function which describes the number of heads and tails. This simple model can be described using the binomial probability distribution function:

set.seed(13)

sample_size <- 1000

trials <- rbinom(1000,size = 100,prob = .5)

trials[c(22,516,843)] <- c(9,88,31)

trial_probs <- pbinom(trials,size = 100,p=.5)



stdev <- sqrt(100*.5*(1-.5))



plot_data <- data.frame(1:1000, trials)



names(plot_data ) <- c("Ind","value")

freaks <- subset(x = plot_data,subset = plot_data$Ind %in% c(22,516,843))



ggplot(plot_data) + geom_point(aes(x = Ind,y= value))+

geom_point(data = freaks,aes(x = Ind,y= value),colour = "red")+

geom_hline(yintercept = qbinom(p = .99,size = 100,prob = .5,lower.tail = FALSE))+

geom_hline(yintercept = qbinom(p = .99,size = 100,prob = .5,lower.tail = TRUE))

Most of the data falls nicely within the top and bottom most lines of the graph which mark where 99% of our outcomes should fall. I also added a few completely unfair results to the data that was plotted — we can recognize these by finding the likelihood that we would obtain each of these observations from a binomial probability distribution:

Additionally, we do see that we have 19 observations which lie outside of the 2 standard deviations, so we may want a stronger measure depending on what our application is.

Anomaly Detection with a Market Model

The previous example is simple: We use the mean and some simple properties of the probability distribution function to identify cheating in our 1000 trials. As it turns out, we can identify suspicious games by simply looking for the values which lie far enough from the mean as to be extremely unlikely. In the case above, our artificial “cheater” experiments have the probabilities of 1.66^-18}, 1.27^-16, and 9.15^-5.

Let’s add one other detail to make things slightly more complicated: Let’s say that instead of doing simple binomial trials like above, we perform a set of trials where the mean of the distribution changes over time. If we do this, the strategy above won’t work as well since the central measure that we are using to determine outliers is changing. In this case, we need to instead define some expected value for the company’s returns using a market model. We will use a OLS regression model to calculate the returns in order to be consistent with finance literature regarding the distribution of security returns.

Abnormal Returns/Residuals

As it turns out, employing a regression model employs similar reasoning as this second numerical example above. In the same way, we attempt to identify what the center of the distribution should be and the size of the standard deviation for the distribution. In this case, the statistical model we use to describe the returns tends to be ordinary least squares:

We find the difference between the actual returns versus the model returns in the same manner as example 2, first by calculating the abnormal returns (residuals):

Calcuating the T-stats

In order to create a meaningful measure of how far our residual lies from the expectation defined by our regression model. This turns out to be a fairly simple procedure: It turns out that we can identify meaninful deviations from our model using the fact that we assume that the errors are assumed to be distributed normally. If we do this, we can apply a simple t-test to the residuals using the standard error the regression model, σσ, as the denominator:

Cumulative Access Returns

symb_eval <- function(x){as.data.table(eval(parse(text = x)))}



pct <- function(x){

inds <- (is.na(x))

returns <- x[!inds]/Lag(x[!inds])-1

ret_x <- x

ret_x[!inds] <- returns

return(ret_x)

}



tickers <- c("CHK","SPY","SLB")

getSymbols(tickers,src = "google") Company <- symb_eval(tickers[1])

Company[,`Company Returns` := lapply(X = .SD,FUN = pct),.SDcols = grep(x = names(Company),pattern = "Close")]



MKT <- symb_eval(tickers[2])

MKT[,`Market Returns` := lapply(X = .SD,FUN = pct),.SDcols = grep(x = names(MKT),pattern = "Close")]



IND <- symb_eval(tickers[3])

IND[,`Index Returns` := lapply(X = .SD,FUN = pct),.SDcols = grep(x = names(IND),pattern = "Close")]



Model_Data <- Reduce(f = function(x,y){ base::merge(x,y,by="index")}, x = list(Company,MKT,IND))



# It looks like we are missing a few days. There isn't much to be done about this aside from being aware of it:

Company$index[!Company$index %in% Model_Data$index] # Train the regression model from the period 1/1/2013 to 12/31/2014:



mkt_model <- lm(data =Model_Data,formula = `Company Returns`~`Market Returns`+`Index Returns`,

subset = (Model_Data$index >= as.Date("2015-06-01") & Model_Data$index <= as.Date("2015-12-31")))



evt_study <- data.frame(Model_Data[,grep(x = names(Model_Data),pattern = "Return|index"),with=FALSE],

predict(object = mkt_model,newdata = Model_Data))



names(evt_study)[c(1,5)] <- c("Date","Predicted Returns")

SE <- summary(mkt_model)$sigma



evt_study$Residuals <- evt_study$Company.Returns-evt_study$`Predicted Returns`

evt_study$`T-Stat` <- evt_study$Residuals/SE



evt_study <- as.data.table(evt_study)



test_begin <- as.Date("2016-01-01")

test_end <- as.Date("2016-06-01")



evt_subset <- evt_study[Date >= test_begin & Date <= test_end]

g1 <- subset(evt_subset,abs(`T-Stat`) >6)



ggplot(data = evt_subset) + geom_point(aes(x = Date,y = `T-Stat`))+

geom_point(data=g1,aes(x = Date,y = `T-Stat`), colour="red")+

geom_hline(yintercept = 1.96)+geom_hline(yintercept = -1.96)+

geom_hline(yintercept = 2.58)+geom_hline(yintercept = -2.58)

feb_stat <-evt_study[Date==as.Date("2016-02-08"),`T-Stat`]

apr_stat <-evt_study[Date==as.Date("2016-04-12"),`T-Stat`]

I picked Chesapeake because it’s a company that has had a lot of interesting news in the past year. I we look at the plot I posted above we see that 2/8/2016 has a t-stat of -7.42 . This makes sense given that on that day there were rumours that the company was hiring restructuring attorneys. 4/12/2016 has a positive return which is almost as significant (6.97) after it was revealed that the banks financing the company would not take away their line of credit. Obviously Chesapeake Energy was having a bump ride at the time (hence the other significant days) but since this is a post on performing the calculations for an event study, I’ll leave off on an in-depth analysis of the company.

Issues Involved with Event Study Analysis

This was a very brief and mostly numerical treatment of event studies. While this example concerns only one company, in academia an event study is often performed on a large group of companies. Another example could be factors in the business environment which contribute to abnormal returns, but are not related to the events we are trying to study (these are called confounding events). This departs from the statistical properties of the model and concerns the researcher’s knowledge of the circumstances of the company they are investigating however.

References:

[1] The Econometrics of Financial Markets: Campbell, Lo, MacKinlay at https://pdfs.semanticscholar.org/aac6/83a678a12a3dcd73389aac7289868847ea73.pdf