Le signal prédit-il quelque chose ?
Avant de bâtir une stratégie sur un signal, demandez s'il pointe dans la bonne direction. Chaque jour, un signal donne un score à chaque action, et un jour plus tard chaque action a un rendement. Le coefficient d'information (IC) est la corrélation, entre actions, du score et du rendement ultérieur. Il va de -1 à 1 ; zéro signifie aucun pouvoir prédictif. Les vrais signaux sont faibles : un IC de 0,02 à 0,05 est déjà utile, car il se répète sur de nombreuses actions et de nombreux jours.
import numpy as np
signal = np.array([0.3, -1.2, 0.8, 0.1, 1.5]) # today's score for five stocks
returns = np.array([0.01, -0.02, 0.005, -0.004, 0.03]) # their returns over the next day
s = signal - signal.mean()
r = returns - returns.mean()
ic = np.sum(s * r) / np.sqrt(np.sum(s ** 2) * np.sum(r ** 2)) # the Pearson correlation
print(round(float(ic), 4))
print(round(float(np.corrcoef(signal, returns)[0, 1]), 4)) # the same numberIC de rang : robuste aux valeurs extrêmes
Une corrélation de Pearson est dominée par les valeurs extrêmes : une action avec un score énorme ou un saut de 40 % en un jour peut la faire basculer. L'IC de rang remplace chaque tableau par le rang de ses valeurs (1 pour la plus petite) et corrèle les rangs. Il demande seulement si les actions que le signal met plus haut finissent plus haut, quelle que soit la taille des nombres, donc il est inchangé par toute transformation croissante du signal. C'est la version que citent la plupart des équipes quantitatives, et c'est la corrélation de Spearman.
# The rank of each value: argsort gives the order, assigning 1..n through it gives the ranks
import numpy as np
values = np.array([30.0, 10.0, 20.0, 5.0])
order = np.argsort(values) # positions from smallest to largest: [3 1 2 0]
ranks = np.empty(len(values))
ranks[order] = np.arange(1, len(values) + 1)
print(order, ranks) # [3 1 2 0] [4. 2. 3. 1.]# Ranks via argsort, and a rank IC that shrugs off an extreme value
import numpy as np
def ranks(values):
order = np.argsort(values)
out = np.empty(len(values))
out[order] = np.arange(1, len(values) + 1)
return out
def ic(a, b):
a, b = a - a.mean(), b - b.mean()
return float(np.sum(a * b) / np.sqrt(np.sum(a ** 2) * np.sum(b ** 2)))
signal = np.array([0.3, -1.2, 0.8, 0.1, 1.5])
returns = np.array([0.01, -0.02, 0.005, -0.004, 0.03])
print(ranks(signal)) # [3. 1. 4. 2. 5.]
print(round(ic(signal, returns), 4), round(ic(ranks(signal), ranks(returns)), 4))
signal_with_outlier = signal.copy()
signal_with_outlier[4] = 1000.0 # one absurd score
print(round(ic(signal_with_outlier, returns), 4), round(ic(ranks(signal_with_outlier), ranks(returns)), 4))La régularité dans le temps : le ratio d'information de l'IC
L'IC d'un jour est bruité. Calculez-le chaque jour pour obtenir une série, et regardez sa moyenne et sa régularité. L'ICIR, l'IC moyen divisé par son écart-type, récompense les signaux justes un peu chaque jour plutôt que très justes quelques jours. C'est un ratio de type Sharpe pour le signal lui-même. Une série quotidienne d'IC de moyenne 0,03 et d'écart-type 0,06 a un ICIR de 0,5.
# A daily rank-IC series for a weak signal, and its ICIR
import numpy as np
def ranks(values):
out = np.empty(len(values))
out[np.argsort(values)] = np.arange(1, len(values) + 1)
return out
def ic(a, b):
a, b = a - a.mean(), b - b.mean()
return float(np.sum(a * b) / np.sqrt(np.sum(a ** 2) * np.sum(b ** 2)))
rng = np.random.default_rng(8)
daily_ics = []
for day in range(250):
signal = rng.normal(size=300) # 300 stocks
returns = 0.01 * (0.05 * signal + rng.normal(size=300)) # the signal explains a sliver of the return
daily_ics.append(ic(ranks(signal), ranks(returns)))
daily_ics = np.array(daily_ics)
print(round(float(daily_ics.mean()), 4), round(float(daily_ics.std(ddof=1)), 4))
print(round(float(daily_ics.mean() / daily_ics.std(ddof=1)), 3))- L'IC est la corrélation entre le signal du jour sur les actions et leurs rendements ultérieurs ; 0,02 à 0,05 est utile, au-dessus de 0,1 est suspect.
- L'IC de rang corrèle les rangs (
argsortdeux fois) : robuste aux valeurs extrêmes et inchangé par toute transformation croissante du signal. - ICIR = IC moyen / écart-type de l'IC sur de nombreux jours : récompense une compétence régulière ; évaluez toujours hors échantillon.
À suivre : la VaR historique, la perte qu'un portefeuille ne doit pas dépasser sauf les pires jours.
Lab : ce qui est noté
- Mettre les valeurs en ordre avec
ranks25 pts - Corréler signal et résultat avec
ic25 pts - Ignorer les valeurs extrêmes avec
rank_ic25 pts - Juger la régularité avec
icir25 pts