Quant Memo
Advanced

Generalization Bounds for Dependent Data

Every standard learning bound assumes your observations are independent draws. Market data is not, so the row count in the formula overstates how much you actually know. This page shows what the honest bound looks like and how much narrower your evidence really is.

Prerequisites: The Generalization Gap, Hoeffding's Inequality, Stationarity

Everything you have ever been told about what a backtest proves rests on one assumption that market data does not satisfy. Hoeffding's inequality, the VC bound, cross-validation error bars, the whole apparatus of Uniform Convergence of Empirical Risk — each derivation opens with "let the observations be independent and identically distributed". Tuesday's market is not independent of Monday's. Volatility clusters, order flow persists, regimes last for months, and if you built your features from overlapping windows then consecutive rows literally share most of their raw ingredients.

So the honest question is not whether the bounds break. They do not. It is that the sample size inside them shrinks, often by a factor of five or ten, and every conclusion you drew from the original row count has to be re-drawn from the smaller one.

The analogy: the survey that called the same houses

A polling firm reports 1,000 responses and a margin of error of three points. Then you learn how it was collected: they dialled 250 households and interviewed all four residents of each. Nobody lied, nobody was double-counted, the fieldwork was clean. But housemates vote alike. The number on the box is 1,000; the number of genuinely independent opinions is nearer 250, and the honest margin of error is twice as wide as advertised.

Dependent data is that survey. Your dataset has exactly as many rows as it has rows. What it does not have is that many independent facts.

Where the standard bound spends its sample size

Take a loss that lives between 0 and 1 — classification error is the easy case, since every row scores either 0 or 1. Write R^\hat{R} for the error rate you measured on your data and RR for the error rate you will actually suffer in future. For independent rows, Hoeffding's inequality says that with probability at least 1δ1-\delta,

R^R    ln(2/δ)2n\lvert \hat{R} - R \rvert \;\le\; \sqrt{\frac{\ln(2/\delta)}{2n}}

In plain English: the gap between the score on your data and the score in real life shrinks like one over the square root of the number of observations, and δ\delta is the small chance you are willing to be wrong about that. The symbol nn is doing all the work, and the derivation earns it by assuming each row brings news nobody else brought.

When rows are correlated, the right substitution is the effective sample size — the number of independent rows that would have carried the same information:

neff  =  n1+2k1ρkn_{\text{eff}} \;=\; \frac{n}{1 + 2\sum_{k \ge 1} \rho_k}

In plain English: divide your row count by how long the series remembers itself. Here ρk\rho_k is the correlation between two observations kk steps apart, so the sum in the denominator is a memory length. If the series forgets instantly every ρk\rho_k is zero, the denominator is 1, and you get your rows back.

Worked example 1: overlapping windows

You are testing whether a signal predicts the direction of the next five days. You have five years of daily data, so n=1,250n = 1{,}250 rows, and each row is a five-day forward window that starts one day after the previous one. Your signal calls the direction right 54 percent of the time.

Consecutive rows share four of their five days. Working through the correlation sum for overlapping windows of length hh gives a denominator of exactly hh, so

neff  =  1,2505  =  250n_{\text{eff}} \;=\; \frac{1{,}250}{5} \;=\; 250

In plain English: sampling a five-day return every day rather than every five days gave you five times the rows and none of the extra information.

Now compute the bound both ways at δ=0.05\delta = 0.05, where ln(2/0.05)=ln40=3.689\ln(2/0.05) = \ln 40 = 3.689.

  • Pretending the rows are independent. 3.689/(2×1,250)=0.001476=0.038\sqrt{3.689 / (2 \times 1{,}250)} = \sqrt{0.001476} = 0.038. Your hit rate is 54%±3.854\% \pm 3.8 points, a range of 50.2 to 57.8. It clears the coin-flip line, so you write it up.
  • Using the effective count. 3.689/(2×250)=0.007378=0.086\sqrt{3.689 / (2 \times 250)} = \sqrt{0.007378} = 0.086. Your hit rate is 54%±8.654\% \pm 8.6 points, a range of 45.4 to 62.6. It contains 50. You have not shown anything.

Same data, same signal, same arithmetic. The only thing that changed is whether you counted rows or counted independent facts.

row 1 row 2 row 3 row 16 day 1 day 11 day 21 4 of 5 days shared
Rows 1, 2 and 3 are three separate lines in your dataframe and almost the same five days of market. Row 16 is the first one that shares nothing with row 1.

Putting a number on "eventually forgets"

Effective sample size is the practitioner's version. Learning theory needs something that works for any model class, not just for an average, and the standard tool is a mixing coefficient. Write β(a)\beta(a) for how far the joint behaviour of "everything up to today" and "everything from aa days later" is from what it would be if the two halves were unrelated.

In plain English: β(a)\beta(a) is how much today still tells you about a day aa steps away. A market with short memory has β(a)\beta(a) collapsing quickly as aa grows; a market stuck in a regime has β(a)\beta(a) near its maximum for a long time. Series where β(a)0\beta(a) \to 0 are called beta-mixing, and essentially every bound for dependent data assumes it.

Drag the rate knob below into negative territory to see the shape people assume for β(a)\beta(a): high at short lags, then falling away. The steeper the fall, the shorter the market's memory, and the less you pay for dependence.

Function explorer
-2227.0
x = 1.00f(x) = 0.449

The trick that converts mixing into a bound is blocking. Cut your nn observations into 2μ2\mu consecutive blocks of length aa. Keep the odd-numbered blocks and throw the rest away. Any two blocks you kept are now aa days apart, so they are nearly independent — off by an amount governed by β(a)\beta(a). Apply the ordinary independent bound to the μ\mu survivors and pay a surcharge for the "nearly":

Pr(R^Rε)    2exp ⁣(2με2)  +  2(μ1)β(a)\Pr\big(\lvert \hat{R} - R \rvert \ge \varepsilon \big) \;\le\; 2\exp\!\big(-2\mu\varepsilon^2\big) \;+\; 2(\mu-1)\,\beta(a)

In plain English: behave as though you had μ\mu independent observations rather than nn, then add a penalty for the fact that they were not quite independent. The first term wants aa small so that μ\mu is large; the second wants aa large so that the blocks are far apart. Choosing aa is the whole game.

n days cut into blocks of length a a keep the green blocks, discard the grey
Blocking buys near-independence by wasting half the data. Every block you keep is separated from the next by a block you threw away.

Worked example 2: choosing the block length

You have n=2,000n = 2{,}000 daily observations and a classifier whose measured error rate is 0.44. Suppose the memory of the series decays as β(a)=e0.35a\beta(a) = e^{-0.35a}, so it has effectively forgotten after about a month. Take δ=0.05\delta = 0.05 and try three block lengths. In each case the mixing surcharge 2(μ1)β(a)2(\mu-1)\beta(a) eats part of the budget, and whatever is left is fed into 2exp(2με2)2\exp(-2\mu\varepsilon^2) to solve for ε\varepsilon.

block length aablocks kept μ\mumixing surchargebudget leftresulting ε\varepsilon
10100198e3.5=5.98198\,e^{-3.5} = 5.98nonevacuous
254078e8.75=0.012478\,e^{-8.75} = 0.01240.03760.223
502038e17.50.00000138\,e^{-17.5} \approx 0.0000010.05000.304

Take the middle row step by step. With a=25a = 25 you get 2μ=802\mu = 80 blocks, so μ=40\mu = 40 survive. The surcharge is 2×39×e8.75=78×0.000158=0.01242 \times 39 \times e^{-8.75} = 78 \times 0.000158 = 0.0124. That leaves 0.050.0124=0.03760.05 - 0.0124 = 0.0376 for the exponential term, so 2exp(80ε2)=0.03762\exp(-80\varepsilon^2) = 0.0376, giving exp(80ε2)=0.0188\exp(-80\varepsilon^2) = 0.0188, then 80ε2=3.97380\varepsilon^2 = 3.973 and ε=0.223\varepsilon = 0.223.

At a=10a = 10 the blocks are too close together and the surcharge alone exceeds 1, which makes the bound say nothing at all. At a=50a = 50 the blocks are gloriously independent but there are only 20 of them, so the statistical term widens. The sweet spot is in between.

Now compare with what the independent bound would have claimed for the same 2,000 rows: 3.689/4000=0.030\sqrt{3.689 / 4000} = 0.030. So the naive reading is "true error is at most 0.47, comfortably better than a coin flip", and the honest reading is "true error is at most 0.66, which is worse than guessing". The classifier may well be fine. The point is that these 2,000 correlated days are not enough to prove it.

Dependence never changes what you are trying to estimate. It changes how much each row is worth. Replace nn by the number of independent observations your data is equivalent to, and every familiar bound keeps working — it just becomes much less flattering.

What this means in practice

Nobody on a desk computes β(a)\beta(a). What they do is take the consequences seriously.

Sample overlapping targets at their horizon, or accept the penalty. If your label is a 20-day forward return, either sample every 20 days or knowingly divide your effective sample by 20 when you judge significance. See Effective Sample Size With Autocorrelated Observations.

Purge and embargo your cross-validation folds. Blocking is exactly what Combinatorial Purged Cross-Validation and Cross-Validation for Time Series implement: leave a gap between train and test so the two are far enough apart to be almost unrelated.

Widen every error bar you inherit. Standard errors from a regression package, Sharpe ratio confidence intervals, and the p-value on a factor loading all assume independence unless you asked for something else. Newey-West HAC Standard Errors is the usual fix on the statistics side.

Expect to need much more history than you thought. The bound scales with 1/neff1/\sqrt{n_{\text{eff}}}, so recovering an error bar four times narrower needs sixteen times the independent sample — and on monthly rebalanced data, twenty years is 240 observations, not 240 thousand.

The classic confusion is believing that a clean out-of-sample split fixes dependence. It does not. Purging stops information leaking from training into testing, which is a different problem. Even a perfectly separated test set gives you a noisy estimate, because the rows inside it are correlated with each other, and it is that internal correlation — not the train/test boundary — that inflates the error bar. A 2,000-day holdout with a one-month memory carries roughly 80 independent observations, and no amount of careful splitting changes that number.

Related concepts

Practice in interviews

Further reading

  • Yu, Rates of Convergence for Empirical Processes of Stationary Mixing Sequences (1994)
  • Mohri & Rostamizadeh, Rademacher Complexity Bounds for Non-i.i.d. Processes (2008)
  • López de Prado, Advances in Financial Machine Learning (Ch. 4 and 7)
ShareTwitterLinkedIn