Triple-Barrier Labelling & Meta-Labelling

Python · NumPy · scikit-learn  ·  Open the notebook

Labelling a Trade Properly

Every earlier example assumed a label existed. In finance, defining the label is itself a modelling decision, and the reflexive choice — "was the 10-day-ahead return positive?" — is a bad one, because it ignores the path. It scores a trade that plunged through a stop-loss before recovering as a win, which no desk would.

The triple-barrier method labels each event by which of three barriers it touches first: an upper profit-take, a lower stop-loss, or a vertical time limit. Barriers scale with recent volatility, so the label reflects a realistic path-dependent outcome. Because each label spans [entry, first touch], consecutive labels overlap — which is precisely why purged cross-validation had to come first.

The width is the method

The barrier width turns out to be the method rather than a parameter. At ±2\pm 2 daily σ\sigma on a horizon whose own standard deviation is σ103.16σ\sigma\sqrt{10}\approx 3.16\sigma, the barriers sit at about ±0.63\pm 0.63 standard deviations of the move being labelled — deliberately tight, and 77.5% of events are decided by a horizontal barrier. Widen them to ±2σ\pm 2\sigma of the full 10-day move and only 6.4% ever touch one: the other 94% run to the time limit and get labelled by the sign of the return, which is exactly the fixed-horizon labelling the method exists to replace. Set the barriers too wide and it quietly degenerates into the thing it was meant to fix.

barrier widthdecided by a horizontal barrierran to the time limit
±2 daily σ as used77.5%22.5%
±2σ of the 10-day move6.4%93.6% — fixed-horizon labelling again

Meta-Labelling, and Choosing the Right Scorecard

Meta-labelling then splits the decision in two. A primary model picks the side; a secondary model predicts whether that bet will win, deciding whether to act and how large. On a controlled example — a primary that wins 78% of the time in one regime and 38% in the other — the meta-model learns to act only where the primary is reliable, lifting precision from 0.57 to 0.78 while trading half as often.

Scoring that correctly requires care, because the obvious summary misses it entirely. F1 stays flat — 0.725, 0.724, 0.727 — since the primary's recall is 1 by construction and every point of precision is paid for one-for-one. Read through F1, meta-labelling appears to accomplish nothing.

The metric that matches the decision is expected profit. A bet won at rate pp returns 2p12p-1 per unit on a symmetric payoff, so the question is what the whole book earns, not what fraction of bets win. Half the bets at four times the edge each is roughly double the total over the same opportunity set. F1 answers a classification question nobody asked.

controlled exampleprecisionfraction tradedF1edge per bettotal edge
primary alone (act on all)0.5681.0000.7250.137274
meta-labelled (thr = 0.5)0.7560.5220.7240.513535
meta-labelled (thr = 0.6)0.7780.4980.7270.556554

And On the Real Market, Nothing

On the real market — S&P triple-barrier labels, 20-day momentum as the primary — the temptation is to read the precision-vs-selectivity curve as a modest success: filter harder, precision drifts up. That curve needs the one thing curves of this shape rarely get, which is error bars. Trading the top 5% of events means estimating a win rate from a few dozen observations.

thresholdn tradedprecision95% intervalclears the 0.532 baseline?
0.458490.5300[0.496, 0.564]no
0.505450.5229[0.481, 0.565]no
0.552670.5206[0.461, 0.581]no
0.581420.5493[0.467, 0.631]no
0.60830.5783[0.472, 0.685]no
0.62460.6522[0.515, 0.790]no

Not one threshold produces a lift that survives its own sampling error. Every interval contains the primary's own precision of 0.532. The curve rises at the selective end because a win rate estimated from 46 events is noisy, not because the filter is finding anything.

Re-running the exercise through the purged, embargoed splitter from the first example — the correct validation for overlapping labels, and a way to see fold-to-fold movement — confirms it. Trading the most-confident quartile in each fold gives lifts of −0.118, +0.047, +0.016, +0.021, +0.057: a mean of +0.005 against a fold-to-fold standard deviation of 0.071, with the sign not even stable across folds.

That is the honest finding, and it matches what Financial Returns Predictability reached by a different route: this primary has no exploitable edge for a meta-model to concentrate. The machinery is correct — the controlled example showed it doubling expected profit where an edge genuinely existed — and it has nothing here to work with. Reporting the curve without intervals would have turned an efficient market into a success story.

Where this sits

This example produces the overlapping labels that Purged & Embargoed Cross-Validation exists to validate, and consumes the stationary-with-memory features built in Fractional Differentiation — the three together are features, labels, and validation. The habit of demanding an interval before believing a curve is the same one applied in Conformal Prediction and Calibration. The precision-for-volume trade also appears in XGBoost, LightGBM & CatBoost, where a selective-prediction rule collapsed under the same scrutiny.

Notebook

Downloads

References