Live-forward divergence

Most alpha-decay detectors cannot detect alpha decay

The standard construction is a CUSUM on daily returns. Losing a full 1.0 of annualised Sharpe — a strategy collapsing — moves the daily mean by 1/√252 ≈ 0.063 standard deviations, and the statistic absorbs 0.5σ of slack before it accumulates anything at all. A shift eight times smaller than the slack never registers. The monitor still fires, on its own false-alarm schedule, and somebody reads noise as a signal.

So this page ships two things that work instead, and says plainly what neither of them can do. Everything runs in this tab; no request leaves it, which is why you can paste a live account into it.

Why the obvious design fails

The obvious tripwire — a CUSUM on daily returns — does not detect alpha decay, and shipping one would be theatre. Losing a full 1.0 of annualised Sharpe moves the daily mean by 1/√252 ≈ 0.063 standard deviations. A textbook CUSUM absorbs 0.5 standard deviations before it accumulates anything at all, so a shift eight times smaller than its own slack never registers: the monitor fires on its false-alarm schedule and an operator reads noise as a signal. What is watched here instead is TRACKING ERROR — live fills against a deterministic replay of the same strategy on the same data. In control that difference is costs and rounding, so its spread is tiny and a real defect is unmissable. A breach means the implementation or the data broke, which is a statement worth acting on.

What a returns CUSUM can actually see

Run at the textbook settings — reference value 0.5σ, decision interval 5σ, one-sided. The last two columns are the pair that describes a monitor: how long it takes to notice a real decay, against how long it takes to cry wolf on its own. When those two numbers are close, every alarm it raises is close to uninformative.

Annual Sharpe lostDaily mean shiftSessions to detectSessions between false alarmsVerdict
0.250.016σ821938blind
0.500.031σ720938blind
1.000.063σ557938blind
2.000.126σ340938eventually

Computed at render by powerReport(), the same function the tool below calls; the run lengths are Siegmund's corrected-diffusion approximation, ported from the engine that minted them. "Eventually" is not the same as "usefully" — the bottom row detects a collapse of two full Sharpe in about 340 sessions, which is more than a year of trading it while it does not work.

The same defect, divided by two different spreads

A leak is not a decay. It is a fixed cost per session that exists in the live path and not in a replay: a fill worse than the model assumed, a fee schedule that changed, a feed that started arriving late, a signal wired up wrongly in production. It is the same absolute number to both monitors — what differs is what it gets divided by. Below, a strategy whose sessions have a 1.0% standard deviation and whose live-versus-replay difference has a 5 basis point one.

Leak per sessionCosts, in annual SharpeWatching returnsWatching tracking error
2 bp0.32463 · 0.020σ60 · 0.4σ
5 bp0.79433 · 0.050σ10 · 1.0σ
10 bp1.59351 · 0.100σ4 · 2.0σ
25 bp3.97140 · 0.250σ1 · 5.0σ

Both columns are the same statistic at the same settings, two-sided, with 469 sessions between false alarms. Nothing about the tracking monitor is cleverer — it is pointed at a series whose in-control spread is small enough for the defect to be large. That is the entire trick, and it is why the pairing matters: the second series has to be a deterministic re-run of the same rules over the same data, not a benchmark.

Where live should sit, and where it actually is

Paste the backtest that convinced you, then the live sessions since. The band is where a strategy with that mean and that spread should be; nothing here raises an alarm, and the reason is in the caveat under the drawing.

Nothing is drawn until a backtest series is supplied. There is no sample curve loaded here on purpose — a band drawn from numbers nobody chose teaches the shape of the tool and nothing about your strategy.

The tripwire: live against its own replay

Two columns, one row per session: what the live account actually returned, and what a deterministic re-run of the same rules over the same data returned. In control that difference is costs and rounding, so its spread is a fraction of the return's and a real break is an enormous standardised shift. The pairing is the whole point — a benchmark in the second column measures nothing.

Tab, comma or space separated — paste two spreadsheet columns straight in. Rows of unequal length are refused rather than aligned by guesswork.

Sessions spent measuring the spread before anything is judged. The spread is then FROZEN — re-estimating it as the series runs would let a slow drift inflate its own denominator and hide inside it. Sixty is the shipped default and the reason is published below: a shorter window makes the monitor fire more often than its own figure promises.

The statistic accumulates only what exceeds its slack: a session half the size of the reference value adds 0.00 to it. That is why a shift smaller than the slack never accumulates at all, whatever its duration.

Nothing runs until both columns are supplied.

Before you trust either: can it see the failure?

A leak of a fixed size per session — a worse fill than modelled, a fee schedule that changed, a feed arriving late — is the same absolute number to both monitors. What differs is what it is divided by. Set the three numbers and the run lengths follow.

basis points

% per session

basis points per session

MonitorThe leak, in σSessions to noticeSessions between false alarms
CUSUM on the strategy's returns0.100σ351469
Tracking error against the replay2.00σ4469

A leak of 10.0 bp a session against a 1.0% session spread costs about 1.59 of annualised Sharpe. The monitor watching returns takes 351 sessions to notice it, against 469 sessions between its own false alarms — so most of what it reports in that window is noise. The monitor watching the tracking error takes 4.

And if that same loss arrives as genuine decay rather than as a leak, the 4 sessions in the row above do not apply at all. A replay of a strategy that stopped working stops working too, so the difference between them stays near zero and the tripwire never fires. What is left is the monitor watching returns: This monitor cannot see a loss of 1.59 Sharpe. That decay moves the daily mean by only 0.100σ, against a reference value of 0.5σ that the statistic absorbs before it accumulates anything. It would take about 351 sessions to notice, against 469 sessions between false alarms — so an alarm from it would carry almost no information.

What the tripwire cannot do, stated first

The tracking monitor is not an alpha-decay detector either, and saying so is the point. It compares live fills against a deterministic replay of the SAME strategy on the SAME data — so when a strategy genuinely stops working, the replay stops working with it, the difference between them stays near zero, and the monitor sits quiet through the entire collapse. What it catches is a leak that exists in the live path and not in the replay: a worse fill than modelled, a fee schedule that changed, a data feed that started arriving late, a signal wired up wrongly in production. Those are the failures that are both common and fixable, and they are invisible to a monitor watching returns. Decay is a different question, and nothing on this page raises an alarm about it, because no statistic can do so in a useful number of sessions. The envelope is drawn instead, and a person looks.

The false-alarm rate is optimistic, by a measured amount

The published false-alarm interval assumes the standard deviation used to standardise each session is KNOWN. Here it is estimated from a calibration window, and a sample standard deviation from a short window is too small about half the time — which inflates every later reading and makes the monitor fire more often than its own figure promises. Measured on in-control data, the alarm rate runs about 1.23x the published rate at a 20-session calibration, 1.17x at 60, and 1.07x at 100, reaching the published rate at roughly 150. Sixty is the shipped default: long enough that the overshoot is modest, short enough to start monitoring inside a quarter. The number is stated rather than smoothed away, because a monitor whose real false-alarm rate is unknown to its operator is worse than none.

What this cannot see

It reads two return series, which are outputs. If the replay is generated by the same broken code as the live path, the two agree perfectly and the monitor is silent while both are wrong — a replay is only evidence to the extent that it is independent of the thing it is checking. If the live returns are reconstructed from statements rather than fills, the tracking error inherits whatever the reconstruction smoothed over.

Nothing here checks the strategy's selection history either. A result that was chosen from a hundred variants and then traded forward will sit inside its own envelope for a long time before the shortfall is large enough to see — which is a question about the search, and the overfitting auditor is where it is asked. A sealed prediction in the pre-registration vault is what makes a live run a test of a claim rather than an observation, and the leaderboard ranks on that basis.

And the envelope's band is drawn under an independence assumption that real returns violate, so it is narrower than the truth. It is drawn rather than alarmed for exactly that reason: a monitor that is confidently wrong about its own error rate is worse than no monitor, and this page would rather hand a person a picture and a caveat than a light that goes green.