Lag Dynamics with Autocopulas
Rakonczai et al. (2010) introduced autocopulas to describe the lag self-dependence structure of a time series. Autocopulas are superior to autocorrelation for the same reasons as copulas are superior to dependence point statistics (e.g. correlation). Readers unfamiliar with copulas are encouraged to review Empirical Copulas and Hedge Basis Risk. Generalizing this notion to arbitrary time series provides an insightful tool for analyzing and visualizing lag dynamics for both individual securities and baskets.
Autocopulas are potentially applicable to all sorts of fun problems in portfolio and risk management, exemplified in this post by considering their applicability to the continuing series on proxy / cross hedging. Further application to generating alpha is fairly straightforward, although left an exercise for readers.
To begin, generalizing autocopulas—as defined by Rakonczai et al.—is necessary to support arbitrary time series (i.e. eliminating stationarity assumption), in doing so introducing explicit dependence on :
Definition 1. Given a time series and set of lags
, the autocopula
is defined as the copula on the
dimensional random vector
.
Definition 2. The l-lag autocopula is the autocopula with lag
.
In other words, an autocopula is the empirical copula composed of one or more lags of the same data series, such as longitudinal returns for an individual equity. From this definition, we can define the stationary versions from Rakonczai et al., suitably relaxing dependency on :
Definition 3. A stationary autocopula is an autocopula whose time series is stationary.
Definition 4. A stationary l-lag autocopula is an l-lag autocopula whose time series is stationary.
Given these definitions, autocopulas can now be applied to proxy / cross hedging.
Individual Autocopulas
The following plots illustrate fitted empirical student-t autocopula densities for the daily returns of CRM with lags of 1 day, 2 days, 1 week, and 1 month:
These plots illustrate an interesting result: strong self-dependence of conditional returns extends over all periods in the tails (in all four corners), with weak dependence outside the tails. In other words, likelihood of large absolute returns is high when preceded by a large absolute return—thus, exhibiting large-magnitude temporal volatility clustering. As Gappy commented, recall the unconditional returns are heavy tailed—as exhibited by the fitted t marginals with low df in the previous post.
Peakedness decreasing with increasing lag indicates dependence decay over time, meaning probability of large absolute returns decrease over time conditional on the previous occurrence of large absolute return (absolute due to peakedness in all four corners). Thus, not only does CRM have long tails, but its tail exhibit decaying temporal tail dependence (and thus, also, potentially self-similar volatility). Thanks to Gappy for absolute returns interpretation.
Compare graphical intuition from above autocopulas versus autocorrelation (ACF) and partial autocorrelation (PACF) functions for absolute returns of CRM, which exhibit similar temporal dependence, yet do so via a pointwise dependence statistic providing minimal graphical intuition:
In contrast with non-absolute returns, which exhibit no such dependence:
Autocopulas for QQQ with same lags:
Indicating that QQQ exhibits similar decaying temporal tail dependence, although the temporal decay is dramatically smaller for QQQ versus CRM—as the density remains strong peaked across all lags.
Proxy Autocopulas
Given autocopulas of the individual securities, question is how to apply this methodology to support intuition about inter-temporal dependence of both assets in proxy hedging. Two approaches seem immediately obvious: excess returns and difference in autocopulas.
First, consider the excess autocopula which is the autocopula of the excess returns, defined as the linear difference in (non-log) returns between individual security
and market index
:
The following illustrates the excess autocopula for CRM and QQQ:
Which illustrates quite different results than above autocopulas of individual securities, on the conditional returns:
- Asymmetric tail dependence: lag-1 dependence in tails is strongly asymmetric, indicating temporal dependence is stronger for the tail of inversely correlated returns
- Rapid asymmetric tail decay: tail asymmetry decays by lag-2, indicating rapid decay
- Rapid dependence decay: temporal dependence decays rapidly, with comparatively minimal peakedness within one week (i.e. lag-5)
Compare this insight with ACF / PACF for excess absolute returns, which exhibit similar behavior as excess autocopula, but do so using only pointwise dependence:
Finally, a second approach to evaluating autocopula dynamics for proxy hedging is the proxy autocopula , which is arithmetic difference of two autocopula densities
and
:
The proxy autocopulas for CRM/QQQ, with same lags as above, are plotted below:
Illustrating lag-1 CRM autocopula has significantly less tail temporal dependence, while having slightly more non-tail temporal dependence. Further, the tail dependence is highly asymmetric with stronger bias to inversely correlated returns. In other words, that suggests inverse return bounces are followed by reversals.
The lag-2 exhibits similar dynamics, although the asymmetric tail dependence is inverted, biased in favor of directly correlated returns.
Lag-5 exhibits similar dynamics as lag-2:
Finally, tail dependence becomes symmetric by lag-22, but otherwise exhibits similar dynamics as lower lags:
Collectively, the above proxy autocopulas clearly visualize the self-dependence of proxy absolute returns with strongly decaying temporal tail dependence.
R code to generate the above autocopula lag dynamic analysis:
exploreProxyAutoCopula <- function(p)
{
# Visualize autocopulas for two proxy instruments and excess.
#
# Args:
# p: matrix of daily instrument price data, including valid colnames
#
# Returns: none
pROC <- ROC(p, type="discrete", na.pad=FALSE)
cnames <- colnames(pROC)
exploreMultiAutoCopula(coredata(pROC[,1]))
exploreMultiAutoCopula(coredata(pROC[,2]))
excess <- pROC[,1]-pROC[,2]
colnames(excess) <- c(paste(cnames[1],"-",cnames[2]))
exploreMultiAutoCopula(coredata(excess)) # excess returns
absReturns <- abs(pROC[,1])
absExcess <- abs(excess)
acf2(absReturns,max.lag=30)
acf2(absExcess,max.lag=30)
plotCopulaDiff(fitAutoCopula(coredata(pROC[,1]),1), fitAutoCopula(coredata(pROC[,2]),1), xlab="", ylab="", zlab="Density Diff", main="Lag-1 Proxy Autocopula")
plotCopulaDiff(fitAutoCopula(coredata(pROC[,1]),2), fitAutoCopula(coredata(pROC[,2]),2), xlab="", ylab="", zlab="Density Diff", main="Lag-2 Proxy Autocopula")
plotCopulaDiff(fitAutoCopula(coredata(pROC[,1]),5), fitAutoCopula(coredata(pROC[,2]),5), xlab="", ylab="", zlab="Density Diff", main="Lag-5 Proxy Autocopula")
plotCopulaDiff(fitAutoCopula(coredata(pROC[,1]),22), fitAutoCopula(coredata(pROC[,2]),22), xlab="", ylab="", zlab="Density Diff", main="Lag-22 Proxy Autocopula")
}
plotCopulaDiff <- function(c1, c2, n = 51, theta = 35, phi = 25, expand = 0.618, ...)
{
# Plot difference in copula perspective for two copulas
xis <- yis <- seq(0, 1, len = n)
grids <- as.matrix(expand.grid(xis, yis))
funDiff <- dcopula(c1, grids) - dcopula(c2, grids)
zmat <- matrix(funDiff, n, n)
persp(xis, yis, zmat, theta = theta, phi = phi, expand = expand, ...)
}
exploreMultiAutoCopula <- function(vec)
{
# Visualize lag-1, lag-2, lag-5, and lag-22 autocopulas for a vector of
# data.
#
# Args:
# vec: vector of data
#
# Returns: empirically fitted copulas
oldpar <- par(mfrow=c(2,2))
cnames <- colnames(vec)
lag1Copula <- fitAutoCopula(vec,1)
lag2Copula <- fitAutoCopula(vec,2)
lag5Copula <- fitAutoCopula(vec,5)
lag22Copula <- fitAutoCopula(vec,22)
persp(lag1Copula, dcopula, main="Lag-1 Autocopula", xlab=cnames[1], ylab="lag-1", zlab="Density", expand=1)
persp(lag2Copula, dcopula, main="Lag-2 Autocopula", xlab=cnames[1], ylab="lag-2", zlab="Density", expand=1)
persp(lag5Copula, dcopula, main="Lag-5 Autocopula", xlab=cnames[1], ylab="lag-5", zlab="Density", expand=1)
persp(lag22Copula, dcopula, main="Lag-22 Autocopula", xlab=cnames[1], ylab="lag-22", zlab="Density", expand=1)
par(oldpar)
return (list(lag1=lag1Copula, lag2=lag2Copula, lag5=lag5Copula, lag22=lag22Copula))
}
fitAutoCopula <- function(vec, lag=1)
{
# Analyze auto copula for a vector of data, with given lag.
#
# Args:
# vec: vector of data
# lag: order of lag, default to 1
#
# Returns: list of copula fit and empirical copula
lagV <- lag(vec, k=lag)
lagV <- lagV[(lag+1):nrow(lagV)]
lagged <- cbind(vec[1:(nrow(vec)-1)],lagV)
colnames(lagged) <- c(colnames(vec)[1], paste("lag-",lag,sep=""))
return(fitEmpiricalCopula(lagged))
}
fitEmpiricalCopula <- function(pROC)
{
# Fit empirical copula, given series of return data.
#
# Args:
# pROC: matrix of daily instrument return data, including valid colnames
#
# Returns: empirical copula
n <- nrow(pROC)
tau <- cor(pROC, method="kendall")[2]
t.cop <- tCopula(tau, dim=2, dispstr="un", df=3)
psuedo <- apply(pROC, 2, rank) / (n + 1)
fit.mpl <- fitCopula(t.cop, psuedo, method="mpl", estimate.variance=FALSE)
return (empiricalCopula <- tCopula(fit.mpl@estimate[1], dim=2, dispstr="un", df=fit.mpl@estimate[2]))
}
acf2 <- function(series, max.lag=NULL)
{
# ACF function replacing broken version from stats library, fixed to
# remove lag=0; credit to David Stoffer (http://www.stat.pitt.edu/stoffer).
num=length(series)
if (is.null(max.lag)) max.lag=ceiling(10+sqrt(num))
if (max.lag > (num-1)) stop("Number of lags exceeds number of observations")
ACF=acf(series, max.lag, plot=FALSE)$acf[-1]
PACF=pacf(series, max.lag, plot=FALSE)$acf
LAG=1:max.lag/frequency(series)
minA=min(ACF)
minP=min(PACF)
U=2/sqrt(num)
L=-U
minu=min(minA,minP,L)-.01
old.par <- par(no.readonly = TRUE)
par(mfrow=c(2,1), mar = c(3,3,2,0.8),
oma = c(1,1.2,1,1), mgp = c(1.5,0.6,0))
plot(LAG, ACF, type="h",ylim=c(minu,1),
main=paste(deparse(substitute(series))))
abline(h=c(0,L,U), lty=c(1,2,2), col=c(1,4,4))
plot(LAG, PACF, type="h",ylim=c(minu,1))
abline(h=c(0,L,U), lty=c(1,2,2), col=c(1,4,4))
on.exit(par(old.par))
ACF<-round(ACF,2); PACF<-round(PACF,2)
return(cbind(ACF, PACF))
}










The autocopulas graphs show symmetric peaks at the four corners, which decrease in magnitude with the delay. Otherwise stated a) the *unconditional* returns are heavy-tailed; b) the probability of a large *absolute* lagged return is high, conditional of high *absolute* return; c) this probability decreases with the lag. a) is well known; b) is also well-known: to make an apples-to-apples comparisons, you should plot the ACF of *absolute* returns, not of returns. This will also give you more intuition about point c), about the rate of decay of any dependence measure.
One more note: exhibiting decaying temporal tail dependence is neither necessary nor sufficient for a process to be self-similar. Brownian processes are self-similar and exhibit no decaying tail dependence; some GARCH processes may exhibit decaying tail dependence without being self-similar.
Working with (moments of) absolute returns points to the fact that it is the volatility process that may be non-trivially self-similar.
@gappy: thanks for insightful comment, as always. Absolute returns is a nice way to express interpretation of symmetric peaks; updating post to incorporate this perspective, with attribution.
Reblogged this on Convoluted Volatility – StatArb,VolArb; Macro..