Breadth: are 31 signals actually 31 signals? (labtrader/signals.py, labtrader/factors.py)
The neutral construction removed the market factor and volatility barely moved,
which killed the variance-reduction half of the argument. That left breadth:
IR = IC × √breadth only pays the square root if the bets are independent.
Thirty-one signals that all say "buy what went up" are one bet with thirty
spare copies.
labtrader/signals.py holds 31 signals across six declared families —
momentum, reversal, volatility, liquidity, technical, shape — drawn from the
published anomaly literature. Every one states the prior that fixes its sign
before seeing data, because choosing signs afterwards is 31 free parameters
and would fit anything. Two pairs (illiquidity/small_dollar_vol,
dist_200ma/ma_cross_50_200) are deliberate near-duplicates: positive
controls for the matrix.
labtrader/factors.py measures two different correlations, because they can
disagree and the disagreement is informative:
- score correlation — do two signals rank the same names on the same day?
- IC correlation — do two signals win and lose on the same days? This is the one that governs portfolio variance.
The headline is effective_breadth: the participation ratio of the
correlation matrix's eigenvalues, (ΣΛ)²/ΣΛ². It equals N for N independent
signals and 1 for N identical ones, so it is directly the number that belongs
under Grinold's square root — not the count in the catalog.
python correlations.py --universe large
This uses forward returns as a label, which is future data no strategy can
see. That is legitimate here because nothing here trades: it is a one-time
measurement of the library, taken to decide whether to keep building. The
docstring says loudly that migrating this arithmetic into a propose() makes
it look-ahead.
Controls first
The instrument is tested against a signal that is the forward return (must measure IC ≈ 1) and against pure noise (must measure IC ≈ 0 and effective breadth ≈ the signal count). An instrument that cannot see a perfect edge cannot be trusted when it reports none, and one that finds structure in noise would flatter every result.