Aller au contenu

09 · Validation statistique

Le chapitre Données historiques et backtest donnait les sept biais à éviter. Celui-ci donne la méthodologie qui permet de prouver qu'il reste quelque chose une fois les biais retirés.

Elle vient essentiellement des travaux de Marcos López de Prado. Le fil rouge : les recettes standard de validation supposent des observations indépendantes et identiquement distribuées. Les données financières ne le sont pas. Les recettes standard y sont donc fausses par construction, pas approximativement justes.

Pourquoi ce chapitre est indispensable ici

Le chapitre Ce que dit la recherche établit qu'aucun motif d'order flow n'a de validation publiée. Vous devez donc produire la vôtre. Une validation faite avec les mauvais outils statistiques ne vaut pas mieux que pas de validation — elle vaut moins, car elle donne confiance.

Le code Python pur de toutes les formules de ce chapitre est en annexe, fichier metrics.py, testé.

Étiqueter : la triple barrière

La méthode naïve étiquette un signal par « le prix a-t-il monté après N barres ? ». Elle ignore le chemin parcouru : un vrai trade touche son stop bien avant l'échéance.

La triple barrière pose trois lignes autour de chaque entrée :

Barrière Rôle
Haute Objectif de gain, souvent proportionnel à la volatilité récente
Basse Stop
Verticale Limite de temps

Le label est donné par la première barrière touchée : \(+1\), \(-1\), ou \(0\) à l'échéance.

def triple_barrier(prices, entry_idx, side, tp_ticks, sl_ticks, max_bars,
                   tick_size):
    entry = prices[entry_idx][0] if side > 0 else prices[entry_idx][1]
    tp = entry + side * tp_ticks * tick_size
    sl = entry - side * sl_ticks * tick_size
    mfe = mae = 0.0

    for i in range(entry_idx + 1, min(entry_idx + 1 + max_bars, len(prices))):
        hi, lo = prices[i]
        fav = (hi - entry) if side > 0 else (entry - lo)
        adv = (entry - lo) if side > 0 else (hi - entry)
        mfe = max(mfe, fav / tick_size)
        mae = max(mae, adv / tick_size)

        touched_sl = (lo <= sl) if side > 0 else (hi >= sl)
        touched_tp = (hi >= tp) if side > 0 else (lo <= tp)
        # Conservateur : si les deux barrières sont touchées dans la même barre,
        # on suppose le stop d'abord.
        if touched_sl:
            return -1, i - entry_idx, mfe, mae
        if touched_tp:
            return 1, i - entry_idx, mfe, mae

    return 0, min(max_bars, len(prices) - 1 - entry_idx), mfe, mae

L'hypothèse conservatrice sur la barre ambiguë

Quand une barre touche le stop et l'objectif, on ne sait pas lequel est venu en premier sans données intrabarre. Supposer le stop sous-estime la stratégie. C'est la seule direction d'erreur acceptable.

Sur des barres de volume courtes, ce cas est rare. Sur des barres de 5 minutes, il est fréquent — raison de plus pour travailler en barres de volume, comme recommandé au chapitre Delta, footprint et CVD.

Des barrières trop serrées n'étiquettent que du bruit

Si la distance au stop est du même ordre que le grésillement normal des prix, les labels ne portent aucune information. Calibrez les barrières sur la volatilité récente, pas sur un nombre de ticks fixe.

La fonction retourne aussi la MFE et la MAE, qui servent directement à calibrer objectif et stop — voir Métriques de l'edge.

Le méta-étiquetage

Architecture en deux étages, particulièrement adaptée à l'order flow :

Modèle primaire  →  direction (acheter/vendre)
     règle codée, réglée pour être généreuse
                 ↓
Modèle secondaire →  prendre ce signal ? à quelle taille ?
     apprend à prédire si le signal primaire sera gagnant

On remplace un problème très dur — prédire le marché — par un problème plus facile : trier les signaux d'une règle existante. La probabilité fournie par le méta-modèle sert directement à doser la taille de la position.

C'est le pont naturel entre ce rapport et l'apprentissage automatique

Vos motifs d'order flow (absorption, imbalances empilées) sont le modèle primaire. Ils sont déjà écrits, testés et interprétables. Le méta-modèle apprend le contexte dans lequel ils fonctionnent — heure, volatilité, régime, distance au VWAP — c'est-à-dire exactement les filtres du chapitre Filtres de contexte et risque, mais appris plutôt que devinés.

C'est nettement plus prometteur que d'entraîner un réseau à prédire le prix à partir du carnet brut, et cela reste explicable.

Le méta-modèle hérite des défauts du primaire

Il doit être validé avec la même rigueur, et le filtrage a un coût : on renonce à certains trades gagnants pour éviter beaucoup de perdants. Ce compromis se mesure, il ne se suppose pas.

Valider : purge, embargo, CPCV

La validation croisée standard découpe les données en \(k\) blocs et suppose les observations indépendantes. En finance, c'est faux : un label triple-barrière s'étale sur plusieurs barres, donc deux observations voisines partagent de l'information. Le modèle est testé sur des données qu'il a partiellement vues.

Trois correctifs, cumulatifs :

Correctif Ce qu'il fait
Purge Retire de l'entraînement toute observation dont le label chevauche la période de test
Embargo Retire en plus une fenêtre juste après le bloc de test (~1 % des données)
CPCV Génère toutes les combinaisons de blocs entraînement/test, purge et embargo à chaque fois

Le gain du CPCV : on obtient une distribution de la performance sur de nombreux chemins de backtest, au lieu d'un chiffre unique facile à sur-optimiser.

L'ordre de grandeur de l'erreur

Un modèle testé en validation croisée naïve peut afficher 58 % de prédictions correctes et tomber à 51 % avec purge et embargo. Les 7 points d'écart ne sont pas du talent : c'est de l'information qui fuit des blocs d'entraînement vers le bloc de test.

Sept points, sur un signal d'order flow, c'est la différence entre une stratégie rentable et une stratégie qui paie des commissions.

Implémentation : purgedcv, compatible scikit-learn.

Juger : le Sharpe dégonflé

C'est le cœur du chapitre, et le point le moins connu des praticiens.

Le problème

La recherche elle-même gonfle le ratio de Sharpe. Testez 500 variantes d'une stratégie sur le même historique, et la meilleure affichera un Sharpe impressionnant même si toutes sont sans valeur. C'est le problème des tests multiples.

Le Sharpe maximal attendu par pur hasard

\[ \mathbb{E}[\max SR] \approx \sqrt{V[SR]} \left[(1-\gamma)\,\Phi^{-1}\!\left(1-\tfrac{1}{N}\right) + \gamma\,\Phi^{-1}\!\left(1-\tfrac{1}{N e}\right)\right] \]
Symbole Signification
\(N\) nombre d'essais effectués pendant la recherche
\(V[SR]\) variance des Sharpe observés sur l'ensemble des essais
\(\gamma\) constante d'Euler-Mascheroni, \(\approx 0{,}5772\)
\(\Phi^{-1}\) quantile de la loi normale centrée réduite

Valeurs calculées par metrics.py, avec \(V[SR] = 0{,}5\) :

Essais Sharpe attendu par hasard
10 1,11
50 1,61
100 1,79
500 2,16
1 000 2,30
5 000 2,61

Lisez ce tableau attentivement

Après 1 000 essais, un Sharpe de 2,30 est le résultat attendu du pur hasard. Si votre meilleure variante affiche 2,0 après avoir balayé une grille de paramètres, vous n'avez rien trouvé — vous avez trouvé moins que ce que le hasard produit.

Un balayage de grille sur 5 paramètres à 6 valeurs chacun, c'est 7 776 essais. Personne ne compte ses essais honnêtement, et c'est précisément pour cela que la plupart des backtests publiés ne valent rien.

PSR et DSR

Le Probabilistic Sharpe Ratio est la probabilité que le vrai Sharpe dépasse un seuil, en tenant compte de la longueur de l'historique et de la forme des rendements :

\[ \text{PSR}(SR^{*}) = \Phi\!\left( \frac{(\widehat{SR} - SR^{*})\sqrt{n-1}} {\sqrt{1 - \hat\gamma_3 \widehat{SR} + \frac{\hat\gamma_4 - 1}{4}\widehat{SR}^{2}}} \right) \]

où \(\hat\gamma_3\) est l'asymétrie et \(\hat\gamma_4\) l'aplatissement des rendements.

Le Deflated Sharpe Ratio est simplement le PSR dont le seuil \(SR^{*}\) est le Sharpe maximal attendu par hasard, calculé ci-dessus.

def deflated_sharpe(returns, n_trials, var_sharpe):
    """Compter TOUS les essais, brouillons compris."""
    return probabilistic_sharpe(returns,
                                expected_max_sharpe(n_trials, var_sharpe))

Le seul paramètre difficile est le comptage des essais

Ne comptez pas seulement les variantes « sérieuses ». Chaque combinaison de paramètres regardée compte, y compris celles jetées après trois secondes.

Conséquence pratique : tenez un compteur d'essais dans votre code de recherche, incrémenté automatiquement à chaque backtest lancé. C'est cinq lignes, et c'est la seule façon d'avoir un chiffre honnête. Le compter de mémoire à la fin donne systématiquement un chiffre trop bas d'un ordre de grandeur.

La longueur minimale d'historique

Corollaire brutal de la formule précédente : avec assez d'essais sur un historique court, on trouve toujours une stratégie au Sharpe séduisant.

\[ \text{MinBTL} \approx \frac{\left(\mathbb{E}[\max SR]\big|_{V[SR]=1}\right)^{2}}{SR_{\text{annuel}}^{2}} \]

Années d'historique nécessaires, calculées :

Essais SR visé 1,0 SR visé 1,5 SR visé 2,0
10 2,5 ans 1,1 an 0,6 an
50 5,2 ans 2,3 ans 1,3 an
100 6,4 ans 2,8 ans 1,6 an
500 9,3 ans 4,1 ans 2,3 ans
1 000 10,6 ans 4,7 ans 2,6 ans

Confrontation avec la réalité de ce rapport

Vous disposez au mieux de quelques mois de données enregistrées, ou d'un an de MBO Databento. Pour qu'un Sharpe annuel de 1,5 soit crédible sur 2,3 ans d'historique, vous ne pouvez pas dépasser 50 essais.

Cela impose une discipline très inhabituelle : formuler peu d'hypothèses, et les tester une fois. Le balayage de grille est structurellement incompatible avec la quantité de données dont dispose un retail sur les futures.

C'est probablement la contrainte la plus sous-estimée de tout ce rapport.

Les autres garde-fous

Probability of Backtest Overfitting (PBO)

La probabilité que la configuration choisie comme meilleure sur le passé soit en réalité sous la médiane sur données nouvelles. Elle se calcule par une variante combinatoire de la validation croisée.

Un PBO au-delà d'environ 50 % signifie que votre sélection n'a rien capturé de réel.

White's Reality Check et SPA test

Deux tests formels du problème des tests multiples, par rééchantillonnage (bootstrap) :

  • Reality Check (White, 2000) : la meilleure règle d'un univers bat-elle la référence, compte tenu de tout l'univers testé ?
  • SPA test (Hansen, 2005) : version plus puissante, moins faussée quand l'univers contient des règles franchement mauvaises.

Appliquer le test aux seules survivantes annule le test

Gardez la trace des 300 combinaisons essayées, pas seulement des 5 survivantes. C'est précisément le biais que le test est censé corriger.

Poids d'échantillons

Quand les labels triple-barrière se chevauchent, les exemples se répètent partiellement. On pondère chaque exemple par son unicité : la part de la période qu'il est seul à couvrir.

Pourquoi c'est important en order flow

Vos signaux se déclenchent en grappes : plusieurs absorptions dans la même demi-heure de marché agité. Sans pondération, le modèle voit dix exemples indépendants alors qu'il n'y a qu'un seul épisode de marché. Il sur-apprend cet épisode, et ses probabilités deviennent mal calibrées — un « 70 % de confiance » qui n'en vaut que 55.

Le pipeline complet

1. Étiqueter en triple barrière
2. Pondérer par unicité
3. Préparer des features stationnaires
4. Valider en CPCV (purge + embargo)
5. Filtrer par méta-étiquetage
6. Juger au DSR, PBO et SPA
   avec comptage HONNÊTE des essais

C'est lourd. C'est le prix d'un avantage réel — et c'est la seule réponse sérieuse au fait qu'aucun motif d'order flow n'a de validation publiée.

La version allégée, pour commencer

Si ce pipeline vous paraît hors de portée, faites au minimum ceci, qui couvre l'essentiel du risque :

  1. Comptez vos essais (compteur automatique).
  2. Étiquetez en triple barrière plutôt qu'en rendement à horizon fixe.
  3. Calculez le DSR avec le nombre d'essais réel.
  4. Comparez à un tirage aléatoire de même distribution horaire (chapitre Backtest).

Ces quatre étapes tiennent dans metrics.py plus vingt lignes, et elles éliminent la grande majorité des faux positifs.

Résumé

  • Les recettes de validation standard sont fausses par construction sur données financières.
  • La triple barrière étiquette ce qu'un vrai trade aurait vécu, stop compris.
  • Le méta-étiquetage est le pont naturel entre motifs d'order flow et apprentissage automatique.
  • Purge + embargo peuvent retirer 7 points de précision apparente.
  • Après 1 000 essais, un Sharpe de 2,30 est le résultat attendu du hasard.
  • Avec 2 ans de données, vous ne pouvez pas dépasser ~50 essais : le balayage de grille est incompatible avec vos données.
  • Version minimale : compter les essais, triple barrière, DSR, test du hasard.

Chapitre précédent : La boîte à outils · Partie suivante : Économie