The estduy2
package is an implementation of an event study methodology. The event study is a statistical toolbox that allows examining the impact of certain events on the stock valuation of companies. The idea of the event study is to compare the market valuation of companies during an event-free period (called the estimation period) and a period when an event happened (the event period).
In order to complete a full event study one has to:
Select companies of interest
Select dates of the event and the estimation periods
Obtain prices of companies’ stocks
Compute rates of return
Fit a market model to the data
Test the expected returns against observed returns of companies
The estudy2
package provides a set of functions to cover these steps. Functions’ names are self-explanatory and functions should be called consecutively in the following order:
get_prices_from_tickers
returns daily prices for given tickers
get_rates_from_prices
computes rates of returns from prices
apply_market_model
fits a market model to rates of returns data
parametric_tests
and nonparametric_tests
performs parametric and nonparametric tests, respectively
The package is designed to work with one of the data types, namely zoo
, list
, or data.frame
depending on user preference.
The purpose of this vignette is to provide a brief introduction of how to use this package. The illustrative example is the analysis of the impact of the COVID-19 lockdown introduction on seven companies, which could profit from it.
We select seven companies that could profit from COVID-19 lockdown, tickers of which are listed in the code snippet below. The starting and ending date are set to "2019-04-01"
and "2020-04-01"
, respectively, in order to include both the estimation and the event periods. Then, prices of securities should be downloaded. The function get_prices_from_tickers
downloads prices for companies’ tickers between start
and end
date. Under the hood, this function is a wrapper around get.hist.quote
from tseries
. The function can return either Open or Close quote (quote
argument). Also one has to choose the returning class among "list"
, "zoo"
, and "data.frame"
. Further in the vignette we use zoo
objects. We download historical prices of companies with:
library(estudy2)
<- c("AMZN", "ZM", "UBER", "NFLX", "SHOP", "FB", "UPWK")
tickers <- get_prices_from_tickers(tickers,
prices start = as.Date("2019-04-01"),
end = as.Date("2020-04-01"),
quote = "Close",
retclass = "zoo")
For using a single-index market model we also need to download prices of an index (proxy):
<- get_prices_from_tickers("^GSPC",
prices_indx start = as.Date("2019-04-01"),
end = as.Date("2020-04-01"),
quote = "Close",
retclass = "zoo")
Now we need to compute rates of returns form companies’ prices. For this purpose the function get_rates_from_prices
is used, which is an S3 generic function dispatched on prices
argument allowing for list
, zoo
, and data.frame
(the same classes which get_prices_from_tickers
returns). The function computes rates of returns of given prices using either continuous or discrete compounding depending on compounding
argument value. Furthermore, setting multi_day
to TRUE
allows for rates of returns between non-consecutive days (for instance, Friday - Monday rate of return). We calculate rates of returns of companies and the index by:
<- get_rates_from_prices(prices,
rates quote = "Close",
multi_day = TRUE,
compounding = "continuous")
<- get_rates_from_prices(prices_indx,
rates_indx quote = "Close",
multi_day = TRUE,
compounding = "continuous")
To calculate expected rates of returns during the event period we need to train a market model based on date from the estimation period. apply_market_model
goes over each company (column) in rates
and calibrates a chosen model. The function returns a list of S3 returns
class objects, which can be passed to parametric_tests
and nonparametric_tests
. For our case we use the single-index market model:
<- apply_market_model(
securities_returns rates = rates,
regressor = rates_indx,
same_regressor_for_all = TRUE,
market_model = "sim",
estimation_method = "ols",
estimation_start = as.Date("2019-04-01"),
estimation_end = as.Date("2020-03-13")
)
The event study utilizes both parametric and nonparametric tests. Parametric tests are Brown and Warner (1980), Brown and Warner (1985), t-test, Patell (1976), Boehmer (1991), and Lamb (1995) tests. To avoid calling all these tests separately, one can call parametric_tests
with all = TRUE
. The same applies to nonparametric tests, i.e. simple binomial sign, binomial sign, Corrado (1992), rank, modified rank, and Wilcoxon signed rank tests can be called all at once by specifying all = TRUE
in nonparametric_tests
. These tests are also available separately. Both functions return data frames with statistics and significance for each date in the event period. See ?parametric_tests
and ?nonparametric_tests
for references and more details.
parametric_tests(list_of_returns = securities_returns,
event_start = as.Date("2020-03-16"),
event_end = as.Date("2020-03-20"))
#> date weekday percentage mean bw_1980_stat bw_1980_signif
#> 1 2020-03-16 Monday 100 0.02329740 2.486449 **
#> 2 2020-03-17 Tuesday 100 -0.03157867 -3.370281 ***
#> 3 2020-03-18 Wednesday 100 -0.01617850 -1.726675 *
#> 4 2020-03-19 Thursday 100 0.07672027 8.188085 ***
#> 5 2020-03-20 Friday 100 0.05840545 6.233409 ***
#> bw_1985_stat bw_1985_signif t_test_stat t_test_signif pt_stat pt_signif
#> 1 1.858514 * 1.3941497 2.5507399 **
#> 2 -2.519140 ** -1.2769075 -2.9495613 ***
#> 3 -1.290615 -0.4023135 0.3283654
#> 4 6.120241 *** 1.7958275 8.4216222 ***
#> 5 4.659205 *** 5.1233281 *** 6.3196352 ***
#> bh_stat bh_signif lmb_stat lmb_signif
#> 1 1.20471169 1.620049
#> 2 -1.17531339 -2.435456 **
#> 3 0.07606284 -1.254626
#> 4 2.16657728 * 6.105794 ***
#> 5 8.65212561 *** 4.565195 ***
nonparametric_tests(list_of_returns = securities_returns,
event_start = as.Date("2020-03-16"),
event_end = as.Date("2020-03-20"))
#> date weekday percentage sign_stat sign_signif gsign_stat gsign_signif
#> 1 2020-03-16 Monday 100 1.1338934 1.1516761
#> 2 2020-03-17 Tuesday 100 0.3779645 0.3957301
#> 3 2020-03-18 Wednesday 100 1.1338934 1.1516761
#> 4 2020-03-19 Thursday 100 1.8898224 * 1.9076220 *
#> 5 2020-03-20 Friday 100 2.6457513 *** 2.6635680 ***
#> csign_stat csign_signif rank_stat rank_signif mrank_stat mrank_signif
#> 1 0.8636930 0.7962064 0.8499246
#> 2 0.2878977 -0.1857202 -0.2283881
#> 3 0.8636930 1.0205417 0.9865178
#> 4 1.4394883 2.1127972 ** 2.1665371 **
#> 5 2.0152836 ** 2.9255529 *** 2.9786668 ***
#> wlcx_stat wlcx_signif
#> 1 23 *
#> 2 10
#> 3 15
#> 4 27 ***
#> 5 28 ***
magrittr
One can notice that the result of the previous function is passed to the next function. In order to avoid naming all the intermediate objects or using a function composition, it possible to utilize a power of the pipe operator from magrittr
. The above code can be rewritten with:
library(magrittr)
<- get_prices_from_tickers("^GSPC",
rates_indx start = as.Date("2019-04-01"),
end = as.Date("2020-04-01"),
quote = "Close",
retclass = "zoo") %>%
get_rates_from_prices(quote = "Close",
multi_day = TRUE,
compounding = "continuous")
<- c("AMZN", "ZM", "UBER", "NFLX", "SHOP", "FB", "UPWK")
tickers
<- get_prices_from_tickers(tickers,
param_tests start = as.Date("2019-04-01"),
end = as.Date("2020-04-01"),
quote = "Close",
retclass = "zoo") %>%
get_rates_from_prices(quote = "Close",
multi_day = TRUE,
compounding = "continuous") %>%
apply_market_model(regressor = rates_indx,
same_regressor_for_all = TRUE,
market_model = "sim",
estimation_method = "ols",
estimation_start = as.Date("2019-04-01"),
estimation_end = as.Date("2020-03-13")) %>%
parametric_tests(event_start = as.Date("2020-03-16"),
event_end = as.Date("2020-03-20"))