*! version 0.1.0

Title

copulaendog -- Instrument-free copula corrections for endogenous
regressors

Syntax

copulaendog depvar endogvars [if] [in],
[options]

Model
exog(varlist) exogenous regressors; factor variables allowed

method(name) pg, 2scope, ima, bmw or
jams; default pg

noconstant suppress the constant term

Copula transformation
cdf(name) marginal CDF estimator; default follows the
estimator's own paper

ties(name) max (default) or average

Inference
nboots(#) bootstrap replicates; default 199

seed(#) random-number seed

level(#) confidence level; default level(95)

Estimator-specific
conditional(varlist) JAMS: variables whose joint categories the
copula structure may vary over

discrete(varlist) JAMS: exogenous regressors to treat as
discrete and keep out of the copula terms

fsexclude(varlist) exogenous regressors to hold out of the
first stage

Reporting
validity report the identification checks

generate(stub) keep the copula terms as variables

endogvars must be plain numeric variables: each one gets its own
copula term, and a factor variable has no single copula term. Put categorical
controls in exog() instead.

Description

copulaendog corrects endogenous regressors in a linear model without an
instrument. The dependence between an endogenous regressor and the structural
error is modelled with a Gaussian copula, and the resulting control function is
added to the regression:

y = mu + P alpha + W beta + C gamma + u,

where C is built from the copula transformation Phi(F(P)) of the
endogenous regressors. The five estimators differ in how C is constructed;
see Estimators below.

Standard errors are bootstrap standard errors from a pairs bootstrap, because
C is a generated regressor and the textbook OLS standard errors are wrong for
the structural coefficients. Resamples that lose a factor level, or that leave
a JAMS category too thin, are rejected and redrawn.

This is a port of the R reference implementation of Rouven E. Haschka,
Copula-based endogeneity corrections in R, and of the packaged version of
it, endogCopula by Ashwin Malshe. Both are credited in full under
References.

Options

Model

exog(varlist) lists the exogenous regressors. They enter the structural
model and, for 2scope, ima and bmw, the first stage. Factor
variables are allowed and are expanded into indicators.

method(name) selects the estimator. See
Estimators.

Copula transformation

cdf(name) chooses how the marginal CDF entering the copula
transformation is estimated. The literature disagrees on this, so all of the
proposals are implemented:

kde.silverman integrated Epanechnikov kernel density, Silverman
bandwidth; Park & Gupta (2012)

kde.plugin Gaussian kernel CDF, Polansky & Baker (2000) plug-in
bandwidth

ecdf.fixed empirical CDF with replaced boundary; Becker, Proksch
& Ringle (2022)

ecdf.adj adjusted ECDF; Liengaard et al. (2025)

rank.n rescaled ECDF, rank/n with a correction; Qian, Koschmann &
Xie (2025)

rank.n1 rank/(n+1); Breitung, Mayer & Wied (2024)

Defaults follow each estimator's own paper: kde.silverman for
pg, rank.n for 2scope and ima, ecdf.adj for
jams, rank.n1 for bmw. bmw is the one place where the
choice is not free: its Proposition 3.1 is derived for rank/(n+1), so anything
else produces a note.

The cross-validated bandwidth of Li, Li & Racine (2017), kde.cv in the R
and Python versions, is not available here.

ties(name) controls the counting function. max reproduces
F(x) = (1/n) sum I(P_i <= x) literally, which is how every one of the papers
writes it. average uses midranks, the convention of the wider copula
literature. The two differ only for tied values.

Estimator-specific

conditional(varlist) applies to jams. The copula structure is
estimated separately within each joint category of the named variables
(Equations 20 and 21 of Liengaard et al.): two binary variables give four
cells, not two. Every copula column is zero outside its own cell. With
conditional() empty, one common structure is estimated (Equation 18).

discrete(varlist) names exogenous regressors that are discrete and
therefore stay out of the copula terms of jams: W in Equation 17 is the
continuous exogenous vector. Indicators produced from factor variables are
detected and excluded automatically.

fsexclude(varlist) holds exogenous regressors out of the first stage of
2scope, ima and bmw while leaving them in the structural
model. Use it for terms built from an endogenous variable, which are not
exogenous information whichever list they were written in.

Reporting

validity reports the identification checks: the non-normality
requirement, the uncorrelatedness assumption where it applies, the shape of
the structural error, and ICON.

generate(stub) keeps the copula terms in the data, named after the
coefficients they belong to, which is what predict, xba needs.

Estimators

method(pg) -- Park & Gupta (2012). The original. Transforms each
endogenous regressor to a normal score and adds it to the regression. Assumes
the endogenous and exogenous regressors are uncorrelated; validity
tests that assumption, because violating it is what motivated the later
estimators.

method(2scope) -- Yang, Qian & Xie (2025). Transforms the
exogenous regressors as well, regresses each P* on W* and uses the residual as
the copula term, so the correction is orthogonal to W by construction. The
first stage carries an intercept.

method(ima) -- Haschka (2025a). 2sCOPE without an intercept in
the first stage, which is what the paper's derivation of rho requires. The two
are usually very close.

method(bmw) -- Breitung, Mayer & Wied (2024). Inverts the order:
the first stage runs on the raw variables and the rank transform is applied to
its residuals. The identification requirement therefore falls on the
first-stage residuals, which is what validity tests, and their
Corollary 3.2 makes the textbook t statistic valid for testing rho = 0, so a
Durbin-Hausman-Wu test is reported next to the bootstrap one.

method(jams) -- Liengaard et al. (2025). Lets the copula
structure differ across the categories of the discrete exogenous regressors;
see conditional().

Examples

Park & Gupta with two exogenous controls

. copulaendog y price, exog(feature display) seed(1)

The same model with the identification checks

. copulaendog y price, exog(feature display) seed(1) validity

2sCOPE, which does not need the uncorrelatedness assumption

. copulaendog y price, exog(feature display) method(2scope) seed(1)

BMW with a factor control and more replicates

. copulaendog y price, exog(feature i.store) method(bmw) nboots(499) seed(1)

JAMS with the copula structure varying over the stores

. copulaendog y price, exog(feature i.store) method(jams) conditional(store) seed(1)

Two endogenous regressors

. copulaendog y price adspend, exog(feature) method(2scope) seed(1)

Structural prediction and residual

. predict yhat

. predict xi, residuals

Stored results

copulaendog stores the following in e():

Scalars

e(N) number of observations

e(nboots) bootstrap replicates actually used

e(df_r) residual degrees of freedom

e(rmse), e(r2), e(r2_a) augmented regression

e(rmse_s), e(r2_s) structural model

e(icon_max) largest standard error inflation

e(xi_skew), e(xi_kurt), e(xi_ad), e(xi_ksp) shape
of the structural error

e(a5_r2), e(a5_F), e(a5_p) joint test of
Assumption 5 (pg only)

Macros

e(cmd) copulaendog

e(method), e(methodlab) estimator

e(endogenous), e(exogenous), e(copnames) variable
groups

e(cdf), e(ties) copula transformation

Matrices

e(b), e(V) coefficients and bootstrap covariance

e(rho), e(rho_se) endogeneity measure

e(b_ols), e(se_ols) uncorrected OLS on the same
resamples

e(icon) standard error inflation

e(diagnostics) skewness, kurtosis, AD, CvM, KS p and the two
boundary-condition flags

e(dhw) Durbin-Hausman-Wu test (bmw only)

e(assumption5) corr(W, copula term) and Holm p values
(pg only)

Author

Girish Mallapragada

Indiana University

LinkedIn |
Google Scholar

This command is a port, developed with the assistance of Claude. The
estimators, and the reference code every one of them is derived from, are the
work of Rouven E. Haschka and Ashwin Malshe; see
References below. Please cite their work, and
the paper behind the estimator you use, in anything this contributes to.

Bug reports and questions:

https://github.com/girishm77/copulaendog_stata_python/issues

References

The implementation this command is ported from:

Haschka, R. E. 2026. Copula-based endogeneity corrections in R.
https://github.com/HashtagHaschka/Copula-based-endogeneity-corrections

Malshe, A. endogCopula: Endogeneity Corrections via Gaussian Copulas.
https://github.com/ashgreat/endogCopula

The estimators:

Becker, J.-M., D. Proksch, and C. M. Ringle. 2022. Revisiting Gaussian copulas
to handle endogenous regressors. Journal of the Academy of Marketing
Science 50: 46-66.

Breitung, J., A. Mayer, and D. Wied. 2024. Asymptotic properties of
endogeneity corrections using nonlinear transformations. The Econometrics
Journal 27(3): 362-383.

Haschka, R. E. 2025a. Robustness of copula-correction models in causal
analysis: Exploiting between-regressor correlation. IMA Journal of
Management Mathematics 36(1): 161-180.

Liengaard, B. D., J.-M. Becker, M. Bennedsen, P. Heiler, L. N. Taylor, and
C. M. Ringle. 2025. Dealing with regression models' endogeneity by means of an
adjusted estimator for the Gaussian copula approach. Journal of the Academy
of Marketing Science 53: 279-299.

Park, S., and S. Gupta. 2012. Handling endogenous regressors by joint
estimation using copulas. Marketing Science 31(4): 567-586.

Polansky, A. M., and E. R. Baker. 2000. Multistage plug-in bandwidth selection
for kernel distribution function estimates. Journal of Statistical
Computation and Simulation 65: 63-80.

Qian, Y., A. Koschmann, and H. Xie. 2025. A practical guide to endogeneity
correction using copulas. Journal of Marketing.

Yang, F., Y. Qian, and H. Xie. 2025. Addressing endogeneity using a two-stage
copula generated regressor approach. Journal of Marketing Research 62(4):
601-623.