Caloogy Article
中文

Factor Testing: IC, Decile Backtesting, and Turnover

Date
Mar 5, 2025
Series
Quant
Reading
5 min
Topics
QuantFactor testingInformation coefficientIcir

The one-sentence version

Once you have built a factor, how do you determine if it is useful? The standard testing toolkit consists of three components:

  1. IC (Information Coefficient): The (rank) correlation between the factor value and the next period's return for each period. It measures "how accurate the ranking prediction is";
  2. Decile Backtesting: Dividing stocks into 5 groups (or 10 groups) based on factor values each period to see if the future returns of each group are monotonic;
  3. Turnover and Decay: How fast the factor rankings change and how long the predictive power lasts. This determines how much alpha remains after deducting transaction costs.

A typical profile of a good factor is: a low IC (0.03 to 0.05 is already very good) but stable (high ICIR); monotonic group returns; and moderate turnover.

Disclaimer

This article is for technical educational purposes only and does not constitute any investment advice. The code in this article uses simulated data.


Layer 1: The Intuition

1.1 The Weather Forecaster's Report Card

To evaluate a weather forecaster, you don't just look at whether they were right on one specific day, but rather:

Factor testing does the exact same thing: IC measures "average accuracy," ICIR measures "stability," and decile backtesting checks "whether the categorization is reasonable."

1.2 Why a Correlation of 0.05 is Considered Good

In daily life, a correlation coefficient of 0.05 is almost equivalent to no relationship at all. However, in the stock market:

This is the intuition behind the "Fundamental Law of Active Management" proposed by Grinold:

IR≈IC×Breadth,\text{IR} \approx \text{IC} \times \sqrt{\text{Breadth}},

The Information Ratio is approximately equal to the "accuracy of each prediction" multiplied by the "square root of the number of independent bets."


Layer 2: Three-Piece Set Explained

2.1 IC

For each period tt:

ICt=Corrrank(fi,t, ri,t+1),\text{IC}_t = \text{Corr}_{\text{rank}}\big(f_{i,t},\ r_{i,t+1}\big),

Using Spearman rank correlation (instead of Pearson) is more robust to outliers.

Metric Meaning Reference
IC Mean Average predictive power Absolute value of 0.02–0.03 is worth considering; above 0.05 is rare
IC Std Dev Volatility —
ICIR = Mean / Std Dev Stability Above 0.5 after annualization is good
Proportion of IC > 0 Win rate Above 60% is better
IC t-statistic Statistical significance Beware of multiple testing issues (see "Multiple Testing and the Factor Zoo")

2.2 Decile Backtesting

Divide stocks into 5 groups based on factor values each period, hold them with equal weights until the next period, and record the returns for each group:

2.3 Turnover and Decay

Concept Calculation Significance
Turnover The proportion of change in portfolio components each period Higher turnover leads to higher transaction costs (see "Transaction Cost Modeling")
Factor Autocorrelation Rank correlation between the current factor value and the previous period's Higher values indicate a "slower" factor and lower turnover
IC Decay IC between the factor and returns for periods 1, 2, 3... in the future Slower decay allows for lower rebalancing frequency

Layer 3: Code Implementation

3.1 Constructing Simulated Panel Data and Calculating IC

Simulate 120 months, with 300 stocks per month, where a true correlation of approximately 0.04 is hidden between the factor and the next period's return:

import numpy as np, pandas as pd
rng = np.random.default_rng(1)
T, N = 120, 300
dates = pd.period_range("2015-01", periods=T, freq="M")
rows = []
for t in dates:
    f = rng.normal(size=N)
    r = 0.04 * f + rng.normal(size=N)        # True IC is approx 0.04
    rows.append(pd.DataFrame({"date": t, "factor": f, "fwd_ret": r * 0.08}))
panel = pd.concat(rows, ignore_index=True)

ic = panel.groupby("date").apply(lambda g: g["factor"].corr(g["fwd_ret"], method="spearman"))
print("IC Mean", round(ic.mean(), 4), "IC Std", round(ic.std(), 4),
      "ICIR (Annualized)", round(ic.mean() / ic.std() * np.sqrt(12), 2), "IC > 0 Ratio", round((ic > 0).mean(), 2))

Output:

IC Mean 0.0465 IC Std Dev 0.06 ICIR (Annualized) 2.69 IC > 0 Ratio 0.77

3.2 Five-Group Backtesting

panel["q"] = panel.groupby("date")["factor"].transform(lambda x: pd.qcut(x, 5, labels=False) + 1)
qret = panel.groupby(["date", "q"])["fwd_ret"].mean().unstack()
print("Monthly average return per group (%)", (qret.mean() * 100).round(3).to_dict())
ls = qret[5] - qret[1]
print("Long-short annualized return (%)", round(ls.mean() * 12 * 100, 2), "Long-short Sharpe", round(ls.mean() / ls.std() * np.sqrt(12), 2))

Output:

Average monthly return per group (%) {1: -0.573, 2: -0.373, 3: -0.063, 4: -0.026, 5: 0.53}
Long-short annualized return (%) 13.24 Long-short Sharpe 2.74

3.3 Interpretation and Real-World Calibration

3.4 Calculating Turnover

def top_quintile_turnover(panel):
    tops = panel[panel["q"] == 5].groupby("date")["stock_id"].apply(set)
    prev, out = None, []
    for s in tops:
        if prev is not None:
            out.append(1 - len(s & prev) / len(s))   # proportion of new entrants this period
        prev = s
    return np.mean(out)

(This requires a stock_id column in the panel; the simulated data above generates stocks independently each period with no identity continuity, so the turnover will be close to 80%, which is the case when "the factor has no autocorrelation.")

3.5 What a Testing Report Should Include

Item Content
Basic Statistics Coverage, distribution, correlation with existing factors (size, industry, momentum...)
IC Analysis Mean, ICIR, win rate, IC time series plot, annual IC
Decile Backtesting Net value curves for each group, monotonicity, long-short returns and drawdowns
Stability Performance under different market environments (bull, bear, high volatility) and different stock universes (large-cap, small-cap)
Turnover and Decay Turnover rate, IC decay curve, returns after deducting costs
Incremental Information Regress against existing factors to see if the new factor provides new information

Summary

Tool Question Answered
IC / ICIR How strong and stable is the average predictive power
Decile Backtesting Is the ranking monotonic, and what are the long-short returns
Turnover and Decay How much remains after costs, and what is the appropriate rebalancing frequency
Fundamental Law of Active Management IR ≈ IC × √Breadth: A weak but stable edge can accumulate significantly