Quant Research Guide
Alpha Signal Research
Finding, testing, and validating predictive signals without fooling yourself is the core skill of a quant researcher. The tools โ IC, ICIR, signal decay, deflated Sharpe โ exist specifically to distinguish real edge from statistical noise in a low signal-to-noise environment.
Core Theory
- 1Information Coefficient (IC): the Spearman rank correlation between the signal value at time t and the forward return at t+h. IC ranges from -1 to +1. IC = 0.02 is practically useful in a diversified portfolio; IC > 0.10 is excellent. Use Spearman (rank) not Pearson to be robust to outlier returns.
- 2IC IR (ICIR): mean(IC) / std(IC) measured over a rolling window. Measures signal consistency over time. ICIR > 0.5 is good; ICIR > 1.0 is exceptional. A signal with IC = 0.04 and ICIR = 0.8 is more valuable than IC = 0.08 and ICIR = 0.3 โ consistency compounds.
- 3Signal decay analysis: compute IC at forward horizons h = 1, 5, 10, 21, 63, 126 trading days. Plot IC vs h. A fast decay (IC โ 0 by day 5) means the signal is best for short-term trading with high rebalancing frequency. Slow decay (still positive at 63 days) means monthly rebalancing suffices.
- 4Turnover and after-cost IC: the true test of a signal is net IC after costs. Net IC โ Gross IC ร (1 - Turnover ร Cost/IC_units). A signal with IC = 0.06 but 400% annual turnover at 10bp costs earns less net than IC = 0.04 with 50% turnover.
- 5Deflated Sharpe Ratio (Bailey & Lopez de Prado 2014): adjusts the observed Sharpe for selection bias when testing multiple configurations. DSR = SR ร (1 - ฮณ ร ln(N)) / โT where N is number of trials. A backtest Sharpe of 2.0 from 100 configurations has DSR โ 0.4 โ the strategy is likely noise.
- 6WorldQuant alpha expression style: a signal expressed as a formula over price/volume/fundamental data, evaluated daily for each stock. Example: -rank(ts_arg_max(close, 5)) โ rank the day on which each stock's 5-day high occurred; stocks near their high get low rank (bearish). Must be cross-sectionally neutral, contain no look-ahead, and pass IC tests.
- 7Signal neutralization: raw signals contain unwanted factor exposures (market beta, sector effects). Neutralize by regressing the signal on sector dummies and market beta, taking residuals. This isolates the stock-specific alpha from broad factor effects โ essential before comparing signals with different sector distributions.
- 8Combinability: the value of a new signal to a portfolio of existing signals depends on its correlation with existing signals. A new signal with IC = 0.04 that is uncorrelated with all existing signals adds more value than IC = 0.06 with high correlation. Compute pairwise IC correlations and use this to guide signal selection.
Key Formulas
| 1 | import numpy as np |
| 2 | import pandas as pd |
| 3 | from scipy.stats import spearmanr |
| 4 | |
| 5 | np.random.seed(42) |
| 6 | T = 60 # 60 months |
| 7 | N = 200 # stocks |
| 8 | |
| 9 | # --- Simulate a signal with true IC โ 0.05 at 1-month horizon --- |
| 10 | true_ic = 0.05 |
| 11 | signal = np.random.randn(T, N) # raw signal (cross-sectional) |
| 12 | noise = np.random.randn(T, N) |
| 13 | returns = true_ic * signal + np.sqrt(1 - true_ic**2) * noise # returns correlated with signal |
| 14 | |
| 15 | # Shift signal by 1 to simulate proper look-ahead prevention |
| 16 | signal_df = pd.DataFrame(signal) |
| 17 | return_df = pd.DataFrame(returns) |
| 18 | |
| 19 | # --- Monthly IC (Spearman rank correlation each month) --- |
| 20 | ic_series = pd.Series([ |
| 21 | spearmanr(signal_df.iloc[t], return_df.iloc[t + 1])[0] |
| 22 | for t in range(T - 1) |
| 23 | ]) |
| 24 | |
| 25 | mean_ic = ic_series.mean() |
| 26 | std_ic = ic_series.std() |
| 27 | icir = mean_ic / std_ic |
| 28 | t_stat = mean_ic * np.sqrt(T - 1) / std_ic |
| 29 | |
| 30 | print(f"Mean IC : {mean_ic:.4f}") |
| 31 | print(f"IC Std : {std_ic:.4f}") |
| 32 | print(f"ICIR : {icir:.4f}") |
| 33 | print(f"IC t-stat: {t_stat:.2f} ({'Significant' if abs(t_stat) > 3 else 'Below t=3 threshold'})") |
| 34 | |
| 35 | # --- Rolling 24-month ICIR --- |
| 36 | rolling_icir = ic_series.rolling(24).apply(lambda x: x.mean() / x.std()) |
| 37 | print(f"\nRolling ICIR (last 12m): mean={rolling_icir.tail(12).mean():.3f}") |
| 38 | |
| 39 | # --- Signal Decay Table --- |
| 40 | horizons = [1, 5, 10, 21, 42, 63] |
| 41 | decay_ics = {} |
| 42 | |
| 43 | for h in horizons: |
| 44 | ics = [] |
| 45 | for t in range(T - h): |
| 46 | fwd_ret = return_df.iloc[t:t+h].sum() # h-period cumulative return |
| 47 | ic, _ = spearmanr(signal_df.iloc[t], fwd_ret) |
| 48 | ics.append(ic) |
| 49 | decay_ics[h] = np.mean(ics) |
| 50 | |
| 51 | print("\nSignal Decay Table:") |
| 52 | print(f"{'Horizon':>8} | {'IC':>8} | {'% of 1d IC':>10}") |
| 53 | print("-" * 32) |
| 54 | for h, ic in decay_ics.items(): |
| 55 | pct = ic / decay_ics[1] * 100 if decay_ics[1] != 0 else 0 |
| 56 | print(f"{h:>8}d | {ic:>8.4f} | {pct:>9.1f}%") |
| 57 | |
| 58 | # --- Cross-signal correlation (combinability) --- |
| 59 | signal2 = np.random.randn(T, N) * 0.3 + signal * 0.7 # correlated signal |
| 60 | ic2 = pd.Series([ |
| 61 | spearmanr(signal2[t], returns[t + 1])[0] |
| 62 | for t in range(T - 1) |
| 63 | ]) |
| 64 | print(f"\nIC correlation between signals: {ic_series.corr(ic2):.3f}") |
| 65 | print("High IC correlation => low diversification benefit from combining") |
The full signal research workflow: monthly Spearman IC computation with proper look-ahead prevention, rolling ICIR for consistency assessment, signal decay table across multiple horizons (which determines optimal rebalancing frequency), and cross-signal IC correlation to assess combinability.
Worked Interview Problems
3 problemsProblem
A researcher presents a signal with mean monthly IC = 0.04, ICIR = 0.6 over 5 years, and IC decay reaching zero at 21 days. Evaluate this signal.
Solution
IC significance: t-stat = 0.04 ร โ60 / (0.04/0.6) = 0.04 ร 7.75 / 0.0667 = 4.65. Significantly above the t = 3 threshold. The IC is real.
ICIR = 0.6 is good โ above the 0.5 threshold for a consistent signal. The IC doesn't vary wildly across months.
Decay to zero at 21 days (1 month) means the signal's edge is fully captured by monthly rebalancing. Rebalancing more frequently doesn't help; rebalancing less frequently loses alpha.
Practical value: using Fundamental Law, with BR = 200 stocks ร 12 months = 2400 bets/year: IR = 0.04 ร โ2400 = 0.04 ร 49 = 1.96. Excellent theoretical IR.
However: subtract transaction costs. If average one-way turnover = 20% monthly and costs = 10bp: cost drag โ 0.20 ร 2 ร 0.001 ร 12 = 0.48%/yr on a typical position. Still leaves substantial net alpha.
Answer
This is a strong signal. IC = 0.04 with t = 4.65 is statistically convincing. ICIR = 0.6 shows consistency. Monthly rebalancing is optimal. Theoretical IR โ 1.96; after costs likely 1.0โ1.5. Research memo ready.
Common Mistakes
Computing IC with Pearson correlation instead of Spearman. Extreme return outliers (earnings surprises, halts) heavily distort Pearson IC. Spearman rank IC is robust to these and is the industry standard.
Not shifting the signal before computing IC. The signal on date t must be computed using only data available at t-1. A common error: using the same-day return in a rolling window that computes the 'signal'.
Treating the in-sample ICIR as the out-of-sample expectation. In-sample ICIR is inflated by selection bias (you're reporting the best-looking version of the signal). The out-of-sample ICIR is typically 30-50% lower.
Ignoring the correlation between signals when building a multi-signal model. Two signals with IC = 0.04 each contribute less than 2ร the single-signal alpha if they are correlated. Always compute pairwise IC correlations before combining.
Claiming a signal is 'significant' based on IC alone without computing the IC t-stat. IC = 0.04 over 24 months has t = 0.04 ร โ24 / ฯ_IC โ 1.5 โ not significant. Need at least 5 years of monthly data for most signals.