Information horizon
Every alpha is perishable: its forecasting power (IC) decays over time at a rate that
is an intrinsic property of the signal. src/alphas/horizon.py measures that decay and
turns it into two free wins — a principled rebalance cadence and a lagged blend
that raises the information ratio.
A diagnostic over an existing alpha's decay structure; it places no orders.
Decay and half-life
IC measured at increasing lags n (the alpha at t vs the residual return realized
n periods later) follows:
IC(n) = IC₀ · δ^n half-life HL = −ln 2 / ln δ
fit_decay fits δ by log-linear regression on the reliable, positive-IC lags and
reports the fit R² — a low R² means the decay isn't a clean exponential, so don't
over-trust the half-life. Because value added scales with IR², the value-added
half-life is half the IC half-life — stale alphas are more damaging than they look.
Cadence and the breadth↔frequency tradeoff
IR(Δt) = IC(Δt) · √(1/Δt)
Rebalancing faster raises √BR but acts on less-confirmed information (lower IC) and
costs more. The optimum is interior: recommended_cadence returns the Δt that
maximizes this IR proxy, so the cadence is chosen, not assumed. The half-life is also
the holding period transaction cost should be amortized over —
closing that spec's "what holding period?" gap.
The optimal current/lagged blend
Given decay γ (= δ) and the signal's autocorrelation ρ, the IR-maximizing weight on
the current signal is:
w_now = (1 − γ·ρ) / (1 + γ² − 2·γ·ρ) w_lag = 1 − w_now
δ > ρ→ diversify:w_lag > 0— the lag carries independent information.δ < ρ→ hedge:w_lag < 0— it mostly cancels current noise.δ = ρ→ the latest signal alone is sufficient.
Matching signal to return horizon
A signal of half-life HL predicts returns best at a horizon ≈ 1.26·HL (where the
signal-return correlation peaks). Surfaced as peak_return_horizon so a short-horizon
signal isn't scored against a long-horizon return — a common way to understate real
skill.
Caveats it surfaces
- Decay should be measured out-of-sample — fitting it on the selection data overstates persistence.
- The blend adds turnover — its lagged leg is priced through the cost
model and
blend_recommendedis only true when the blend diversifies and its annual turnover cost is modest; a high-turnover blend that would lose net is flagged. - Regime-dependent decay — the half-life isn't constant; re-estimate on a rolling window rather than freezing one number.
Where it runs
services.compute_horizon measures the IC-vs-lag profile (reusing the
information-analysis forward-residual machinery), fits the
decay, and recommends the cadence + blend. The CLI (python main.py horizon) and the
read-only MCP tool compute_horizon route through it.