Cross-Correlation

An online retailer notices that a burst of search queries for "winter coat" reliably shows up about two weeks before a jump in coat sales. If they could measure that lead precisely they could stock the warehouse just in time. This is the everyday job of cross-correlation: given two time series, at what lag does one most strongly track the other, and which one leads? The autocorrelation function asked how a series relates to its own past; cross-correlation asks how one series relates to another series' past and future.

Cross-covariance and the CCF

For two jointly stationary series x_t and y_t, the cross-covariance function at lag h is

\gamma_{xy}(h) = \operatorname{Cov}(x_t,\; y_{t+h}) = \mathbb{E}\big[(x_t - \mu_x)(y_{t+h} - \mu_y)\big].

Standardize it by the two individual standard deviations and you get the cross-correlation function (CCF), a dimensionless number in [-1, 1]:

\rho_{xy}(h) = \frac{\gamma_{xy}(h)}{\sqrt{\gamma_{xx}(0)\,\gamma_{yy}(0)}} = \frac{\gamma_{xy}(h)}{\sigma_x \sigma_y}.

With the convention above, a nonzero value at lag h says: the value of x now is correlated with the value of y h steps later. Slide h across a range of lags, plot the result, and the shape tells you the lead–lag structure at a glance.

The crucial asymmetry

An autocorrelation function is always symmetric: \rho_x(h) = \rho_x(-h), because "how does today relate to h steps away" doesn't care which direction you look. The CCF is not symmetric — and that asymmetry is the entire point:

A symmetric CCF would tell you two series move together but not who moves first. The lopsidedness is what encodes the direction of timing — the coat searches peaking before the coat sales, not the other way round.

A CCF that leans right

The stem plot below is the sample CCF of two series where x drives y with a two-step delay. Notice it is not centred on lag zero: the tallest stem sits at h = +2, and the values decay away on either side of that peak. Everything to the right of zero is telling you about x's future influence on y; the small, fast-fading values to the left rule out the reverse story.

Worked example: reading a peak at lag +2

Suppose a study of two indicators reports a sample CCF that is small and flat everywhere except for a clear spike \hat\rho_{xy}(2) = 0.7, with much smaller values at h = 1 and h = 3 and essentially nothing at negative lags. Read it step by step:

Operationally: to forecast y you should put lagged x in the model. That is precisely the intuition Granger causality will formalize into a test.

Cross-correlation is even more prone to the spurious-relationship trap than ordinary correlation. If x and y each carry a trend or are strongly autocorrelated, the sample CCF will light up with large, smooth, "significant"-looking values at many lags — even when the two series have nothing to do with each other. The reason is subtle: the usual \pm 1.96/\sqrt{n} significance bands assume at least one series is white noise, and heavy autocorrelation inflates the true variance of \hat\rho_{xy}(h) far beyond that. The fix is prewhitening: fit a model to x to reduce it to (near-)white residuals, apply the same filter to y, and compute the CCF of the two filtered series. Only after prewhitening does a CCF peak actually mean what you think it means. Interpreting a raw CCF between two trending series is the same mistake as a spurious regression in stem-plot clothing.

Almost — and the near-miss trips people up. Cross-correlation slides one signal past another and multiplies: (x \star y)(h) = \sum_t x_t\, y_{t+h}. Convolution does the same but with one signal reversed: (x * y)(h) = \sum_t x_t\, y_{h-t}. That flip is exactly why convolution is symmetric (x*y = y*x) while cross-correlation is not. Engineers use cross-correlation to find the delay between two copies of a signal — sonar, GPS, matching a template to an image — which is the same lead–lag question a statistician asks of two time series, wearing a different hat.