Type: Package
Title: Synthetic Matching Method for Returns
Version: 1.0.0
Description: Implements the revised Synthetic Matching Algorithm of Kreitmeir, Lane, and Raschky (2025) <doi:10.2139/ssrn.3751162>, building on the original approach of Acemoglu, Johnson, Kermani, Kwak, and Mitton (2016) <doi:10.1016/j.jfineco.2015.10.001>, to estimate the cumulative treatment effect of an event on treated firms’ stock returns.
License: MIT + file LICENSE
Encoding: UTF-8
URL: https://github.com/davidkreitmeir/synthReturn
BugReports: https://github.com/davidkreitmeir/synthReturn/issues
RoxygenNote: 7.3.2
Imports: base (≥ 4.0.0), stats, utils, corpcor (≥ 1.6.10), data.table, quadprog (≥ 1.5), parallel, mirai
Depends: R (≥ 4.0)
LazyData: true
Suggests: knitr, rmarkdown, testthat (≥ 3.0.0)
Config/testthat/edition: 3
NeedsCompilation: no
Packaged: 2025-09-02 01:30:27 UTC; david
Author: David H Kreitmeir [aut, cre], Christian Düben [ctb]
Maintainer: David H Kreitmeir <david.kreitmeir1@monash.edu>
Repository: CRAN
Date/Publication: 2025-09-08 18:40:02 UTC

Simulated timeseries of stock returns

Description

ret_two_evdates presents a simulated timeseries of stock returns for 20 treated firms and a set of 60 potential control firms. The simulated data allows for a max estimation window of 100 trading days (in event time: -100 to -1) and a max event window of 6 trading days (in event time: 0 to +5).

Usage

ret_two_evdates

Format

ret_two_evdates has 14,000 rows and 5 variables:

eventdate

Calendar date when the event happened (⁠<Date>⁠).

date

Calendar date (⁠<Date>⁠).

ret

Raw stock return (⁠<num>⁠).

treat

Binary treatment indicator (⁠<lgcl>⁠).

unit

Unique identifier for each treated, respectively control firm (⁠<int>⁠).


Simulated timeseries of stock returns

Description

ret_two_evdates_num presents a simulated timeseries of stock returns for 20 treated firms and a set of 60 potential control firms. The simulated data allows for a max estimation window of 100 trading days (in event time: -100 to -1) and a max event window of 6 trading days (in event time: 0 to +5).

Usage

ret_two_evdates_num

Format

ret_two_evdates_num has 14,000 rows and 5 variables:

eventdate

Numeric date when the event happened (⁠<int>⁠).

date

Numeric date (⁠<int>⁠).

ret

Raw stock return (⁠<num>⁠).

treat

Binary treatment indicator (⁠<lgcl>⁠).

unit

Unique identifier for each treated, respectively control firm (⁠<int>⁠).


Compute synthetic returns

Description

synthReturn implements the revised Synthetic Matching Algorithm of Kreitmeir et al. (2025), building on the original approach of Acemoglu et al. (2016), to estimate the cumulative treatment effect of an event on treated firms’ stock returns.

Usage

synthReturn(
  data,
  unitname,
  treatname,
  dname,
  rname,
  edname,
  estwind,
  eventwind,
  estobs_min = 1,
  eventobs_min = 1,
  inference = c("none", "permutation", "bootstrap"),
  correction = FALSE,
  ncontrol_min = 10,
  ndraws = 25,
  ncores = NULL,
  static_scheduling = TRUE
)

Arguments

data

The name of the data frame that contains the data.

unitname

The name of the column containing IDs of treated and control units.

treatname

The name of the indicator column set to TRUE for the treatment group and to FALSE for the control group. The column's values must be time-constant within a unit because they mark whether a unit was ever treated.

dname

The name of the column containing the date variable. The column must either be of type Date or numeric. See details.

rname

The name of the column containing the stock returns.

edname

The name of the column containing the (treatment unit-specific) event date. All event dates must also exist in dname. The column must either be of type Date or numeric. Event date values are ignored for control group units. See details.

estwind

Argument to set estimation window period in relative time to event, i.e. c(estwind_start, estwind_end). 0 is the event date. The interval only considers observed time periods. See details.

eventwind

Argument to set event window period in relative time to event, i.e. c(eventwind_start, eventwind_end). 0 is the event date. The interval only considers observed time periods. See details.

estobs_min

Argument to define minimum number of trading days during the estimation window. Can be an integer or a proportion (i.e. between 0 and 1). Default is 1, i.e. no missing trading days are allowed.

eventobs_min

Argument to define minimum number of trading days during the event window. Can be an integer or a proportion (i.e. between 0 and 1). Default is 1, i.e. no missing trading days are allowed.

inference

Argument to define which inference method is to be used. Both permutation and bootstrap inference are implemented. Default is "none".

correction

Logical defining if "corrected" synthetic matching results are used for inference. If TRUE firms that do not have a good synthetic match, defined as firms in the control group with \sigma more than \sqrt3 times the average \sigma of the treated firms, are excluded. Default is FALSE. correction has no effect if inference = "none".

ncontrol_min

Minimum number of control firms required to create synthetic match. Default is 10.

ndraws

Number of randomly drawn placebo treatment groups if inference = "permutation". Number of nonparametric bootstrap repetitions if inference = "bootstrap". Has to be larger than 1. ndraws has no effect if inference = "none".

ncores

Number of CPU cores to use. NULL (the default) sets it to the number of available cores.

static_scheduling

Logical setting the parallel scheduling type. TRUE (default) implies static scheduling, FALSE dynamic scheduling. This parameter does not change the output object. It only influences the speed of the function. The scheduling choice has no effect when ncores = 1 and in inference = "permutation" estimations on Windows machines.

Details

The data's dname and edname columns refer to dates. dname is the date that a row refers to. edname is the date when a unit was treated. I.e., edname is constant across all rows per unit. And it is ignored for never treated units.

The package does not care what interval a time period refers to. It evaluates units' sequences of distinct Date or numerical values in dname and edname, irrespective of whether they denote days, hours, etc.

estwind and eventwind describe sections in these sequences. 0 is the treatment time. Hence, c(-1, -100) is a unit's 100 observations before treatment. When dname and edname are in days and a specific unit is observed on 2 days per week, c(-1, -100) covers 50 weeks before treatment in the case of that unit. In the case of financial data, that would be a company's 100 trading days before treatment.

Value

An S3 object containing the following components:

n_treat_pre

Number of treatment units in the data.

n_treat_res

Number of treatment units in the data that fulfill the minimum requirements and are used in the calculation of the average treatment effect \phi.

ate

Data.table containing the relative time period \tau and the average treatment effect estimates \phi. If the user selects inference = "permutation", the data.table additionally reports the p-value and the 95 percent confidence interval. If the user selects inference = "bootstrap", the data.table additionally reports the standard error, the p-value and the 95 percent confidence interval.

ar

Data.table reporting the estimated abnormal returns, the "goodness" of the synthetic match estimate \sigma, the weighted cumulative abnormal return and the corresponding weights for all treated firms.

ate_bootstrap

Data.table containing the average treatment effect estimates \phi for each bootstrap iteration. Returned if the user chooses inference = "bootstrap".

n_bootstrap

Number of bootstrap iterations that returned a valid result.

ate_placebo

Data.table containing the average treatment effect estimates \phi for each placebo treatment group draw. Returned if the user chooses inference = "permutation".

n_placebo

Number of placebo draws that returned a valid result.

call

List with arguments used in the call.

Examples


# Load data in that comes in the synthReturn package
data(ret_two_evdates)

# -----------------------------------------------
# Example with Permutation Inference
# -----------------------------------------------

set.seed(123) # set random seed

# Run synthReturn
res.placebo <- synthReturn(
  data = ret_two_evdates,
  unitname = "unit",
  treatname = "treat",
  dname = "date",
  rname = "ret",
  edname = "eventdate",
  estwind = c(-100,-1),
  eventwind = c(0,5),
  estobs_min = 1,
  eventobs_min = 1,
  inference = "permutation",
  correction = FALSE,
  ncontrol_min = 10,
  ndraws = 10,
  ncores = 1
  )

# -----------------------------------------------
# Example with Nonparametric Bootstrap
# -----------------------------------------------

set.seed(123) # set random seed

# Run synthReturn
res.boot <- synthReturn(
  data = ret_two_evdates,
  unitname = "unit",
  treatname = "treat",
  dname = "date",
  rname = "ret",
  edname = "eventdate",
  estwind = c(-100,-1),
  eventwind = c(0,5),
  estobs_min = 1,
  eventobs_min = 1,
  inference = "bootstrap",
  correction = FALSE,
  ncontrol_min = 10,
  ndraws = 25,
  ncores = 1
)

# -----------------------------------------------
# Example with Missing Returns
# -----------------------------------------------

set.seed(123) # set random seed
# Randomly introduce 2% of missing return values
ret_two_evdates[sample.int(nrow(ret_two_evdates), floor(0.02*nrow(ret_two_evdates))), ret := NA]
# Run synthReturn
res.boot <- synthReturn(
  data = ret_two_evdates,
  unitname = "unit",
  treatname = "treat",
  dname = "date",
  rname = "ret",
  edname = "eventdate",
  estwind = c(-100,-1),
  eventwind = c(0,5),
  estobs_min = 0.9, # require 90% of trading days during estimation window w/ non-missing returns
  eventobs_min = 0.9, # require 90% of trading days during event window w/ non-missing returns
  inference = "bootstrap",
  correction = FALSE,
  ncontrol_min = 10,
  ndraws = 25,
  ncores = 1
)