Description: shows how stock returns change before and after an event.

Inputs:  symbols_list, dt_start, dt_end, L1, window

Outputs: PositiveCAR_All.png, NegativeCAR_All.png, PositiveCAR_SUM.png, NegativeCAR_SUM.png

Libraries: Requires pandas_datareader to be installed. In terminal paste “pip install pandas-datareader” uses the following dependencies or libraries.

We begin by creating the function EventStudies(), and we define the list of stock symbols in addition to the start and end dates, which will be used in our analysis. Notice that in the DataReader function, we specify that we want to download the adjusted close prices.

We calculate stock returns from the price data and store them in data_ret as:

The next step is to define an “event.” For stocks, the event can be the earnings announcement, while for currencies, it can be the central bank’s interest rate announcement. Sometimes, an event may occur that affects a company, but is not necessarily announced by that company. This is where trader sentiment can also be used to define an event. One way to do this would be to download Twitter feed about a certain asset, and then calculate a sentiment metric that would indicate whether an event has occurred. However, I do not attempt to do this here. In this example, I define an event occurrence when the difference between the return on the stock and the return on the market is larger than daily_diff:

Using this threshold, I create an events data frame where columns = names of all stocks and rows = daily dates, and iterate over each day for every stock. Positive events, where (daily stock return – market return) > daily_diff take the value of 1, negative events, where (daily stock return – market return) < daily_diff take the value of -1, otherwise no event has occurred.

Now that we have identified the events, we need to calculate the abnormal returns. There are several ways of doing this; however, following MacKinlay (1997), we use the market model in this example. This model is written as R_it = a_i + B_i*R_mt + e_it. In order to estimate this model, we need to define an estimation period L1, and usually the larger the period, the more accurate the model. We also specify a window over which we want to calculate and observe abnormal returns. In our example, we will look at return on the day of the event, as well as pre-window and post-window days. For example, if window = 20, then we will be observing abnormal returns over the 20 days prior to an event, on the day of the event, and 20 days after the event.

Observing returns on days pre and post an event allows us to examine the period over which information is incorporated into stock prices.

Python allows us to store information in dictionaries. Moreover, it allows us to store dictionaries within dictionaries! We start by creating 2 dictionaries of dictionaries, one for positive events and the other for negative events.

Then (the complicated part), for each stock, we locate every positive and negative event separately, and calculate the abnormal returns (AR) for all days in the observation period (i.e. the pre and post window days in addition to the event day). We store the computed abnormal returns over the observation period in an events dictionary, which is stored in a stock dictionary, which is stored in either a positive or negative events dictionary.

Now that we have calculated and stored the abnormal returns in separate dictionaries, we can transfer them into a Pandas data frame for further analysis. To do this, we create 2 empty data frames for the positive and negative events called pos_data_abret and neg_data_abret, respectively. The columns in each data frame represent the stocks, while the rows are the days in the observation period (i.e. 41 days including the event day).

Now that we have the abnormal returns of each stock in a data frame format, we can calculate the cumulative abnormal returns (CAR), which is the variable that we want to examine over time.

Finally, we plot the cumulative abnormal returns for each stock, for positive and negative events, separately. For cumulative abnormal returns of positive events:


For cumulative abnormal returns of negative events:


We can also plot the aggregate cumulative abnormal returns for positive and negative events separately. To do so, we first sum the cumulative abnormal returns across stocks for each day.

For aggregated cumulative abnormal returns of positive events:


For aggregated cumulative abnormal returns of negative events:


Don’t forget to call the function!

This example does not aim to replicate the results of MacKinlay (1997). It just shows how information is incorporated into stock prices well in advance of, and long after an announcement date.