Signal Decay and Half-Life: When Your Alpha Dies
Signal decay is the rate at which a predictive relationship between your feature and forward returns weakens over the holding horizon. Every alpha has a half-life — the horizon at which its information coefficient (IC) falls to half its peak. Ignoring decay is one of the most common ways to overstate backtest Sharpe: you hold a 1-day signal for 5 days and call the extra days "free alpha" when they are actually noise. This article defines decay rigorously, shows how to estimate it from panel data, and connects it to portfolio construction and capacity.
Why decay matters more than IC
The information coefficient — correlation between signal at time t and return from t to t+h — is the standard measure of predictive power. But a signal with IC = 0.05 at h=1 and IC ≈ 0 at h=5 is a completely different animal from one with IC = 0.05 sustained across h=1..20. Decay determines:
- Optimal holding period — how long to stay in a position before the edge is gone
- Turnover budget — fast-decaying signals require more trading to capture the same alpha
- Capacity — high turnover amplifies transaction costs
- Combination weights — slow signals and fast signals should not be blended naively
A useful decomposition:
total_alpha ≈ IC_peak × sqrt(breadth) × sqrt(decay_persistence)
Breadth is the number of independent bets; decay persistence is how long IC stays elevated. Strategies that look brilliant on a 1-day horizon often die on a 20-day horizon because the signal was never slow — you just never measured it.
Measuring decay: the IC horizon curve
For each horizon h (in days or bars), compute the cross-sectional Spearman IC between signal z-scored at t and forward return from t to t+h. Plot IC(h) vs h. Typical shapes:
| Shape | Interpretation | Example |
|---|---|---|
| Sharp drop, flat tail | Fast alpha, mean-reverting noise after h* | Order flow imbalance |
| Slow linear decay | Persistent factor exposure | Value, low-vol |
| Hump | Signal peaks at intermediate h | Momentum with short reversal |
| Flat then cliff | Structural break or event-driven | Earnings drift pre/post announcement |
import numpy as np
import pandas as pd
def ic_by_horizon(signal: pd.DataFrame, prices: pd.DataFrame,
horizons: range = range(1, 21)) -> pd.Series:
"""Cross-sectional Spearman IC at each forward horizon."""
rets = prices.pct_change()
ics = {}
for h in horizons:
fwd = rets.shift(-h).rolling(h).sum() # h-day forward return
aligned = signal.stack().to_frame('sig').join(
fwd.stack().to_frame('ret'), how='inner'
).dropna()
ics[h] = aligned.groupby(level=0).apply(
lambda g: g['sig'].corr(g['ret'], method='spearman')
).mean()
return pd.Series(ics)
# Half-life: smallest h where IC(h) <= IC(1) / 2
def estimate_half_life(ic_curve: pd.Series) -> float:
peak = ic_curve.iloc[0]
below = ic_curve[ic_curve <= peak / 2]
return float(below.index[0]) if len(below) else float('inf')
Run this on out-of-sample windows. In-sample IC curves are optimistically flat because overfitting inflates short-horizon IC without improving long-horizon IC — a signature of data mining.
Half-life from autocorrelation
For a single time-series signal st, the AR(1) model st = φ·s{t-1} + εt gives a half-life of:
half_life = -ln(2) / ln(φ) (for 0 < φ < 1)
For φ = 0.95 (daily), half-life ≈ 13.5 days. For φ = 0.50, half-life ≈ 1 day. This is the continuous-time analogue of the IC curve and is useful when you have a single-asset or single-factor signal rather than a cross-section.
In practice, estimate φ with OLS on the signal itself (not on returns), then convert to half-life. Compare to the IC-based estimate — they should agree directionally. Large disagreement means the signal's predictive power decays faster than its autocorrelation structure suggests (common when the signal is a noisy proxy for a slower latent factor).
Turnover and the decay tax
Expected strategy turnover is approximately:
turnover ≈ 1 / half_life (for mean-reverting signals held to decay)
A signal with half-life = 2 days on a universe of 500 names implies ~250 round-trip position changes per day at full rebalance — before you account for optimal execution. The net Sharpe after costs:
net_SR ≈ gross_SR - turnover × cost_per_trade / sqrt(n_obs)
If gross_SR = 1.5, turnover = 0.5/day, cost = 10 bps round-trip, you lose ~0.5 × 0.001 × sqrt(252) ≈ 0.008 per unit of SR per year from costs alone — and that is before market impact at scale.
Rule of thumb: if IC(1) × sqrt(N) × sqrt(252) / turnover > 3 × cost_bps, the signal might survive costs. Below that, it is research noise dressed as alpha.
Decay-aware portfolio construction
Standard mean-variance or risk parity treats signals as static weights. Decay-aware construction does three things differently:
- Horizon-matched returns — regress signal on the return horizon where IC peaks,
not on 1-day returns if the signal is slow
- Exponential weighting — weight recent signal observations more if φ is high (slow
decay) or use shorter windows if φ is low
- Separate sleeves — combine fast and slow signals with explicit turnover budgets
per sleeve rather than blending into one portfolio
Alpha combination via stacking or meta-labeling should use decay-matched labels: a meta-model predicting "will this signal still work in h days?" is more valuable than one predicting direction alone.
Regime dependence of decay
Decay is not constant. In high-volatility regimes, microstructure signals decay faster (informed flow is absorbed quicker). In low-liquidity regimes, slow signals decay slower (prices take longer to adjust). Test IC(h) conditional on regime:
def ic_by_regime(signal, prices, regime: pd.Series, h=1):
fwd = prices.pct_change().shift(-h)
df = signal.stack().to_frame('sig').join(
fwd.stack().to_frame('ret'), how='inner'
).join(regime.rename('regime'), how='inner')
return df.groupby(['regime', df.index.get_level_values(0)]).apply(
lambda g: g['sig'].corr(g['ret'], method='spearman')
).groupby('regime').mean()
If half-life halves in crisis regimes, your risk model should haircut position sizes accordingly — not just vol-scale but decay-scale.
Research checklist
Before promoting a signal to production:
- Plot IC(h) for h = 1..20 on walk-forward OOS data
- Estimate half-life via IC curve and AR(1) — they should agree within 2x
- Compute turnover implied by half-life and subtract realistic costs
- Test decay stability across regimes and years
- Compare to deflated Sharpe after
accounting for how many horizons you tested
A signal that fails the decay test is not necessarily worthless — it may be a 1-day scalping signal with a clear execution path. But it must be labeled, sized, and costed as such. Pretending it is a monthly factor is how backtests lie.
Key takeaways
- Every signal has a half-life; measure it before you size it
- IC at h=1 tells you almost nothing about economic viability without the full IC curve
- Fast decay implies high turnover, which caps capacity
- Decay-aware construction matches holding periods to where IC peaks
- Regime-conditional decay is as important as regime-conditional volatility
