Page 1 sur 1

Votre edge vient-il du signal ou du sizing ?

Publié : 09 sept. 2026, 12:38
par Anya
Le sizing peut-il rendre profitable une stratégie qui ne l'est pas ?

C'est une idée qu'on croise souvent sur les forums, généralement formulée ainsi : « peu importe le point d'entrée, ce qui compte c'est la gestion ». Elle est à la fois vraie et fausse, et l'écart entre les deux mérite d'être précisé, parce que c'est exactement là que se logent les martingales et les comptes vidés.

Je vais partir d'un cas réel — le mien — et remonter jusqu'aux mathématiques, qui sont plus simples qu'il n'y paraît.

Le point de départ

J'ai analysé 214 positions prises sur GER40 et NAS100 en deux mois de compte réel. Résultat brut : environ 860 € de gain.

Puis j'ai refait le calcul en imaginant que j'avais pris exactement les mêmes positions, aux mêmes moments, dans le même sens, mais toujours avec un lot identique. Résultat équipondéré : +8,60 €.

Autrement dit, mon signal d'entrée ne rapporte rien. Zéro. Le rendement moyen par position est de +0,0003 % du prix, avec un intervalle de confiance à 95 % qui va de −0,020 % à +0,020 %. Je ne peux même pas exclure que ma stratégie soit légèrement perdante.

Et pourtant le compte est en gain, parce que mes grosses positions et mes petites positions ne sont pas réparties au hasard. Voilà le sujet.

Ce que le sizing ne peut pas faire

Commençons par ce qui est mathématiquement impossible, parce que c'est là que la plupart des raisonnements dérapent.

Multiplier toutes vos positions par un même coefficient multiplie votre résultat par ce même coefficient. Si votre espérance est nulle, elle reste nulle. Si elle est négative, elle reste négative et l'écart-type augmente. Trader 3 lots au lieu de 1 ne transforme pas une stratégie plate en stratégie gagnante, ça transforme un bruit de 100 € en bruit de 300 €.

Deuxième impossibilité, plus insidieuse : la martingale, sous toutes ses formes. Doubler après une perte, moyenner à la baisse, ajouter sur une position perdante. Ces méthodes ne changent pas l'espérance. Elles changent la forme de la distribution : elles transforment une série de résultats moyens en une longue suite de petits gains, ponctuée d'une perte catastrophique. L'espérance reste identique, mais elle est désormais concentrée dans un événement rare dont on ne sait pas quand il arrive. Avec les frais, elle devient même strictement inférieure.

Troisième point, celui qu'on oublie presque toujours : une stratégie à espérance arithmétique nulle est une stratégie perdante dès qu'on la compose. Si vous risquez une fraction f de votre capital à chaque trade, votre taux de croissance approche f×μ − f²σ²/2. Quand μ vaut zéro, il ne reste que le terme négatif.

J'ai simulé 4 000 comptes de 250 trades sur une stratégie d'espérance exactement nulle :
  • f = 1 % du capital par trade : capital médian ×0,99, 53 % des comptes en perte
  • f = 5 % : capital médian ×0,71, 66 % des comptes en perte
  • f = 10 % : capital médian ×0,30, 78 % des comptes en perte
  • f = 20 % : capital médian ×0,005, 94 % des comptes en perte
Espérance nulle à chaque trade, et pourtant le compte médian est ruiné à 20 %. C'est le drag de volatilité, et c'est la raison pour laquelle « ma stratégie est à peu près à l'équilibre » n'est pas une position neutre : c'est une position perdante dès qu'on augmente la taille.

Retenons donc : le sizing peut détruire une bonne stratégie, il ne peut pas créer d'espérance à partir de rien. Sauf d'une seule manière.

Ce que le sizing peut réellement faire

Toute l'affaire tient dans une identité de deux lignes. Si X est le résultat d'une position exprimé en points, et v la taille que vous lui avez donnée, alors votre gain est :

E[v × X] = E[v] × E[X] + Cov(v, X)

Lisez bien le second terme. Si votre espérance en points E[X] est nulle, le premier terme disparaît et l'intégralité de votre résultat est la covariance entre votre taille et votre résultat. Rien d'autre.

C'est-à-dire : est-ce que vous mettez plus gros, précisément, sur les trades qui marchent mieux ?

Si oui, vous gagnez de l'argent sur une stratégie d'espérance nulle, et ce n'est pas de la magie. C'est simplement que la variable de taille contient de l'information que le signal d'entrée ne contient pas. Formulé autrement : vous n'avez pas une stratégie qu'on redimensionne, vous avez deux stratégies différentes — les petites positions et les grosses — et vous appelez « sizing » ce qui est en réalité un second signal.

C'est le cas dans mon historique. Mes positions de plus de 2 lots, au nombre de 31, portent la quasi-totalité du résultat. Ce ne sont pas des entrées prises au hasard qu'on aurait grossies : ce sont mes reprises, celles que j'ouvre après qu'une première position a établi le sens du mouvement. Elles bénéficient d'une information que les autres n'ont pas.

C'est aussi ce que formalise le critère de Kelly : la taille optimale n'est pas une constante, c'est une fonction de l'edge du moment. Miser identiquement sur toutes les situations, c'est jeter de l'information.

Le piège : distinguer un sizing informatif d'une simple chance

Voici le vrai problème, et il est presque toujours passé sous silence.

Constater après coup que vos grosses positions ont mieux marché ne prouve rien. Sur 200 trades, il faut bien que la répartition des tailles tombe d'une certaine manière, et elle tombera par hasard sur les gagnants dans un bon nombre de cas.

Le test qui tranche est simple à mettre en œuvre : gardez exactement le même jeu de tailles et le même jeu de résultats, mais redistribuez les tailles au hasard sur les trades. Refaites-le vingt mille fois. Vous obtenez la distribution de ce qu'un sizing aveugle aurait produit. Il ne reste plus qu'à regarder où se situe votre résultat réel dans cette distribution.

Sur mon historique :
  • Distribution des 20 000 réallocations aléatoires : moyenne +6 €, écart-type 838 €, 5e centile à −1 538 €, 95e centile à +1 198 €
  • Mon résultat réel, +861 €, se situe au 87e centile
  • p unilatéral = 0,13, soit 2 623 tirages aléatoires sur 20 000 qui font aussi bien ou mieux
Traduction : mon sizing est peut-être informatif, mais je ne peux pas le démontrer. Un trader qui aurait tiré ses tailles au sort aurait fait mieux que moi dans 13 % des cas. C'est encourageant, ce n'est pas une preuve.

Notez surtout l'écart-type : 838 €, pour un résultat de 861 €. Le simple fait de faire varier les tailles, même sans aucune information, génère une dispersion de résultats du même ordre de grandeur que le gain total. Sur un tel historique, on ne peut essentiellement rien conclure — et c'est précisément dans ce brouillard que naissent les convictions les plus solides.

Les limites du raisonnement

Même en admettant que votre sizing soit réellement informatif, plusieurs objections restent debout.
  • Un edge qui vit entièrement dans le dimensionnement discrétionnaire n'est ni automatisable, ni transmissible, ni robuste. Il dépend de votre état du jour. Un signal d'entrée, on peut le coder et le backtester ; « j'ai senti qu'il fallait mettre plus gros », non.
  • La covariance entre taille et résultat est beaucoup plus instable dans le temps que l'espérance d'un signal. Elle peut disparaître sans prévenir, et vous ne le saurez qu'après plusieurs centaines de trades.
  • Concentrer le capital sur quelques situations concentre aussi le risque. Dans mon cas, ce sont exactement les grosses positions qui ont produit jusqu'à 55 % du solde du compte en perte flottante sur une seule séance. Le rendement et le risque viennent du même endroit.
  • Les frais ne se redimensionnent pas dans le bon sens. Le spread se paie proportionnellement à la taille, mais il pèse d'autant plus que l'espérance par trade est faible. Sur une stratégie à espérance nulle en brut, elle est franchement négative en net.
  • Enfin, la taille d'échantillon. Pour établir un edge de l'ordre de +0,02 % par trade avec la dispersion habituelle de l'intraday indices, il faut compter 1 500 à 2 000 positions. En dessous, on mesure du bruit.
Ce que j'en retiens

La formule vaut d'être gardée en tête, parce qu'elle range tout le débat :

E[v × X] = E[v] × E[X] + Cov(v, X)

Le premier terme, c'est votre stratégie. Le second, c'est votre gestion. Beaucoup de traders qui pensent avoir un edge d'entrée ont en réalité un terme de covariance, et beaucoup de traders qui pensent gérer intelligemment ont un terme de covariance nul et un compte qui survit grâce à un marché porteur.

Le seul moyen de savoir dans quel cas on est, c'est de refaire le calcul à taille constante. C'est cinq minutes de travail sur un export de rapport, et le résultat est rarement flatteur.

Pour ma part, il ne l'a pas été : à taille constante, deux mois de trading valent huit euros et soixante centimes. Ça remet le reste en perspective.

Si certains d'entre vous font l'exercice sur leur propre historique, le chiffre qui m'intéresse est le rapport entre le résultat réel et le résultat équipondéré. Chez moi il est de 100 pour 1. J'aimerais bien savoir si c'est une anomalie ou la norme.

Plusieurs d'entre vous m'ont demandé de publier l'outil. Le voici, en Python, sous licence domaine public. Il fonctionne sur n'importe quel rapport d'historique MetaTrader 5, quels que soient vos instruments et la langue de votre terminal.

Il répond à trois questions, dans cet ordre :
  • Quelle est l'espérance de votre stratégie à taille constante, c'est-à-dire en imaginant que vous ayez pris exactement les mêmes positions avec toujours le même lot ?
  • Quelle part de votre résultat réel vient du dimensionnement plutôt que du signal d'entrée ?
  • Ce dimensionnement porte-t-il réellement de l'information, ou fait-il aussi bien qu'une répartition au hasard des mêmes tailles ?
Récupérer votre rapport

Dans MT5, onglet Historique en bas de l'écran, clic droit n'importe où dans la liste, puis Rapport, puis XLSX. Pensez à afficher la période complète que vous voulez analyser avant d'exporter, sinon vous n'obtiendrez que le mois en cours.

Installation et lancement
  • pip install pandas numpy openpyxl
  • python edge_vs_sizing.py MonRapport.xlsx
Trois options utiles :
  • --symboles GER40.p NAS100.p pour ne garder qu'une famille d'instruments homogène. Indispensable si vous mélangez indices et forex : un lot d'indice et un lot de paire de devises n'ont rien de comparable, et le script vous avertit quand il détecte le cas.
  • --tirages 50000 pour augmenter la précision du test de permutation. Le défaut de 20 000 suffit largement.
  • --graphique pour afficher l'histogramme des permutations avec votre résultat en pointillés. Beaucoup plus parlant que le centile, si vous avez matplotlib installé.
Comment lire la sortie

Le bloc 1 vous donne, par instrument, vos points cumulés et votre résultat ramené à 1 lot partout. C'est votre stratégie nue, débarrassée de tout effet de taille.

Le bloc 2 compare ce résultat équipondéré à votre résultat réel. Si l'écart est énorme, votre performance ne vient pas de vos entrées. Il affiche aussi l'intervalle de confiance à 95 % de votre rendement moyen par position, exprimé en pourcentage du prix pour rester comparable entre instruments. Si zéro tombe dans cet intervalle, vous ne pouvez pas démontrer d'edge d'entrée sur cet échantillon. Ce n'est pas la même chose que ne pas en avoir, mais c'est la seule chose que vos données autorisent à dire.

Le bloc 3 est le cœur du sujet. Le script garde exactement votre jeu de tailles et votre jeu de résultats, puis redistribue les tailles au hasard sur les trades, vingt mille fois. Vous obtenez ainsi la distribution de ce qu'un dimensionnement aveugle aurait produit sur votre propre historique. Il ne reste qu'à regarder où tombe votre résultat réel.

Deux chiffres à surveiller dans ce bloc, et le second est plus important que le premier :
  • Le centile. Au-delà du 95e, votre sizing est difficile à attribuer au hasard. Entre le 80e et le 95e, c'est encourageant sans être concluant. En dessous, il n'apporte rien de démontrable.
  • L'écart-type des réallocations. Il mesure le bruit généré par le seul fait de faire varier les tailles, sans aucune information. S'il est du même ordre de grandeur que votre gain total, votre historique ne permet de conclure à rien, quel que soit le centile affiché. C'est mon cas, et c'est probablement le cas de la majorité d'entre nous.
Sur mon propre historique

Deux mois, 210 positions sur GER40 et NAS100 :
  • Résultat réel : +782,21 €
  • Résultat équipondéré à 1 lot : −16,54 €
  • Rendement moyen par position : −0,0001 %, intervalle de confiance [−0,0203 % ; +0,0200 %]
  • Permutation : 85,5e centile, p = 0,145, soit 2 902 tirages au hasard sur 20 000 qui font aussi bien ou mieux
  • Écart-type des réallocations : 840 €, pour un gain de 782 €
Traduction : mon signal d'entrée ne vaut rien de mesurable, mon dimensionnement est peut-être informatif mais je ne peux pas le prouver, et le bruit est aussi gros que le résultat. Deux mois de trading rentable qui, une fois passés au tamis, ne démontrent absolument rien.

Je serais curieux de voir vos chiffres, en particulier le rapport entre votre résultat réel et votre résultat équipondéré.

Une note sur le calcul

Le script ne vous demande aucune spécification de contrat. Il déduit la valeur du point de chaque symbole à partir de vos propres trades, par la médiane du rapport entre le profit enregistré et le produit points multiplié par lots. Ça fonctionne sur n'importe quel instrument, y compris ceux dont vous ne connaissez pas les specs.

Les points sont calculés à partir des prix d'ouverture et de clôture du rapport, donc déjà nets du spread : MT5 enregistre l'entrée à l'ask et la sortie au bid pour un achat, et l'inverse pour une vente. En revanche les commissions et les swaps ne sont pris en compte que dans la ligne « résultat réel net », pas dans le calcul en points.

Le code

Code : Tout sélectionner

#!/usr/bin/env python3

-- coding: utf-8 --

"""
edge_vs_sizing.py - Votre edge vient-il du signal ou du dimensionnement ?

Prend en entree un rapport d'historique MetaTrader 5 (onglet Historique ->
clic droit -> Rapport -> XLSX) et repond a trois questions :

Quelle est l'esperance de votre strategie A TAILLE CONSTANTE ?
Quelle part de votre resultat reel vient du dimensionnement ?
Ce dimensionnement est-il informatif, ou indistinguable du hasard ?

Le point 3 est un test de permutation : on garde exactement le meme jeu de
tailles et le meme jeu de resultats, on redistribue les tailles au hasard sur
les trades, et on regarde ou tombe le resultat reel dans la distribution
obtenue. Si votre resultat est noye dans le tas, votre sizing n'apporte rien
de demontrable.

Usage :
python edge_vs_sizing.py MonRapport.xlsx
python edge_vs_sizing.py MonRapport.xlsx --tirages 50000 --graphique

Dependances : pandas, numpy, openpyxl (matplotlib seulement pour --graphique)
pip install pandas numpy openpyxl matplotlib

Licence : domaine public. Publie sur le forum VideoBourse.
"""

import argparse
import sys
import warnings

import numpy as np
import pandas as pd

warnings.filterwarnings("ignore", module="openpyxl")

Libelles de la section "Positions" en FR et EN, pour que le script
fonctionne quelle que soit la langue du terminal MT5.

MARQUEURS_DEBUT = ("positions",)
MARQUEURS_FIN = ("ordres", "orders", "transactions", "deals")
COL_ACHAT = ("buy", "achat")

def charger_positions(chemin):
"""Extrait le bloc 'Positions' d'un rapport d'historique MT5 (.xlsx)."""
brut = pd.read_excel(chemin, header=None)

def premiere_cellule(i):
    v = brut.iloc[i, 0]
    return str(v).strip().lower() if pd.notna(v) else ""

debut = fin = None
for i in range(len(brut)):
    cell = premiere_cellule(i)
    if debut is None and cell in MARQUEURS_DEBUT:
        debut = i + 2  # ligne de titre = debut+1, donnees a partir de debut+2
    elif debut is not None and cell in MARQUEURS_FIN:
        fin = i
        break
if debut is None:
    sys.exit("Section 'Positions' introuvable. S'agit-il bien d'un rapport "
             "d'historique MT5 au format xlsx ?")
if fin is None:
    fin = len(brut)

# Colonnes du bloc Positions, dans l'ordre, quelle que soit la langue :
# ouverture | ticket | symbole | type | volume | prix | S/L | T/P |
# cloture | prix | commission | swap | profit
noms = ["t_open", "ticket", "sym", "type", "vol", "p_open", "sl", "tp",
        "t_close", "p_close", "comm", "swap", "profit"]
d = brut.iloc[debut:fin, :len(noms)].copy()
d.columns = noms
d = d[d["sym"].notna() & d["type"].notna()]

for c in ("vol", "p_open", "p_close", "comm", "swap", "profit"):
    d[c] = pd.to_numeric(d[c], errors="coerce")
d = d.dropna(subset=["vol", "p_open", "p_close", "profit"])
d["type"] = d["type"].astype(str).str.strip().str.lower()
d = d[d["type"].isin(("buy", "sell", "achat", "vente"))]
return d.reset_index(drop=True)

def preparer(d):
"""Calcule points, valeur du point et resultat net par position."""
d = d.copy()
d["sens"] = np.where(d["type"].isin(COL_ACHAT), 1, -1)

# Points gagnes/perdus, deja nets du spread : MT5 enregistre l'entree a
# l'ask et la sortie au bid pour un achat, et l'inverse pour une vente.
d["pts"] = (d["p_close"] - d["p_open"]) * d["sens"]

# Valeur du point par lot, deduite des trades eux-memes plutot que
# codee en dur : evite d'avoir a connaitre les specs de chaque symbole.
ecart = d["pts"] * d["vol"]
implicite = (d["profit"] / ecart).replace([np.inf, -np.inf], np.nan)
ref = implicite.groupby(d["sym"]).median()
d["vpp"] = d["sym"].map(ref)
d = d[d["vpp"].notna() & (d["vpp"] > 0)]

d["net"] = d["profit"] + d["comm"].fillna(0) + d["swap"].fillna(0)
d["eur_1lot"] = d["pts"] * d["vpp"]          # resultat a 1 lot partout
d["eur_reel"] = d["pts"] * d["vol"] * d["vpp"]  # resultat brut reconstitue
d["pct"] = d["pts"] / d["p_open"] * 100      # normalise, comparable entre
return d.reset_index(drop=True)              # instruments

def resume_par_symbole(d):
g = d.groupby("sym").agg(
n=("pts", "size"),
points=("pts", "sum"),
pts_par_trade=("pts", "mean"),
reussite=("pts", lambda s: (s > 0).mean() * 100),
eur_1lot=("eur_1lot", "sum"),
eur_reel=("net", "sum"),
)
return g.round(2)

def test_permutation(d, tirages, graine=None):
"""Redistribue les memes tailles au hasard sur les memes trades."""
rng = np.random.default_rng(graine)
pts_vpp = (d["pts"] * d["vpp"]).to_numpy()
tailles = d["vol"].to_numpy()
reel = float((pts_vpp * tailles).sum())

sims = np.empty(tirages)
for i in range(tirages):
    sims[i] = (pts_vpp * rng.permutation(tailles)).sum()

centile = float((sims < reel).mean() * 100)
return reel, sims, centile

def intervalle_confiance(x):
x = pd.Series(x).dropna()
demi = 1.96 * x.std(ddof=1) / np.sqrt(len(x))
return x.mean() - demi, x.mean() + demi

def main():
ap = argparse.ArgumentParser(
description="Signal ou sizing ? Analyse d'un rapport d'historique MT5.")
ap.add_argument("rapport", help="fichier .xlsx exporte depuis MT5")
ap.add_argument("--symboles", nargs="+", default=None, metavar="SYM",
help="ne garder que ces symboles (ex : --symboles GER40.p "
"NAS100.p). Recommande des que vous melangez des "
"familles d'instruments differentes.")
ap.add_argument("--tirages", type=int, default=20000,
help="nombre de permutations (defaut : 20000)")
ap.add_argument("--graine", type=int, default=None,
help="graine aleatoire, pour resultats reproductibles")
ap.add_argument("--graphique", action="store_true",
help="affiche l'histogramme des permutations")
args = ap.parse_args()

d = preparer(charger_positions(args.rapport))
if args.symboles:
    d = d[d["sym"].isin(args.symboles)].reset_index(drop=True)
    if d.empty:
        sys.exit("Aucune position pour les symboles demandes.")
if len(d) < 30:
    print("Attention : moins de 30 positions exploitables, "
          "les resultats ci-dessous n'ont aucune valeur statistique.\n")

print("=" * 68)
print("  %d positions  |  %s  ->  %s" % (len(d), d["t_open"].iloc[0],
                                         d["t_close"].iloc[-1]))
print("=" * 68)

vpp = d.groupby("sym")["vpp"].first()
if len(vpp) > 1 and vpp.max() / vpp.min() > 20:
    print("\nAVERTISSEMENT : vos instruments ont des valeurs de point tres\n"
          "differentes (indices et forex, par exemple). Le calcul a taille\n"
          "constante additionne alors des lots qui n'ont rien de comparable.\n"
          "Relancez avec --symboles pour ne garder qu'une famille homogene.")

print("\n[1] RESULTAT PAR INSTRUMENT, A TAILLE CONSTANTE (1 lot partout)\n")
print(resume_par_symbole(d).to_string())

print("\n[2] SIGNAL OU SIZING ?\n")
reel_net = d["net"].sum()
plat = d["eur_1lot"].sum()
print("  Resultat reel (tailles reelles, net)      : %+10.2f EUR" % reel_net)
print("  Resultat equipondere (1 lot partout)      : %+10.2f EUR" % plat)
if abs(reel_net) > 1e-9:
    print("  Part du resultat due au dimensionnement   : %9.1f %%"
          % ((reel_net - plat) / reel_net * 100))

bas, haut = intervalle_confiance(d["pct"])
print("\n  Rendement moyen par position, en %% du prix : %+.4f %%"
      % d["pct"].mean())
print("  Intervalle de confiance a 95 %%             : [%+.4f %% ; %+.4f %%]"
      % (bas, haut))
if bas < 0 < haut:
    print("  -> Zero est dans l'intervalle : aucun edge d'entree "
          "demontrable sur cet echantillon.")
elif bas > 0:
    print("  -> Edge d'entree positif et significatif sur cet echantillon.")
else:
    print("  -> Edge d'entree negatif et significatif sur cet echantillon.")

print("\n[3] TEST DE PERMUTATION : votre sizing est-il informatif ?\n")
reel, sims, centile = test_permutation(d, args.tirages, args.graine)
p = 1 - centile / 100
print("  Resultat reel (brut, hors frais)          : %+10.2f EUR" % reel)
print("  Moyenne des %d reallocations aleatoires : %+10.2f EUR"
      % (args.tirages, sims.mean()))
print("  Ecart-type de ces reallocations           : %10.2f EUR" % sims.std())
print("  5e centile / mediane / 95e centile        : %+.0f / %+.0f / %+.0f EUR"
      % (np.percentile(sims, 5), np.median(sims), np.percentile(sims, 95)))
print("\n  Votre resultat se situe au %.1f e centile   (p = %.4f)"
      % (centile, p))
print("  %d tirages au hasard sur %d font aussi bien ou mieux."
      % ((sims >= reel).sum(), args.tirages))

if p < 0.05:
    verdict = ("Votre dimensionnement porte de l'information : il est "
               "difficile de l'attribuer au hasard.")
elif p < 0.20:
    verdict = ("Resultat encourageant mais non concluant. Il faut plus de "
               "trades pour trancher.")
else:
    verdict = ("Votre dimensionnement est indistinguable d'une repartition "
               "au hasard des memes tailles.")
print("\n  -> " + verdict)

print("\n  Rappel : l'ecart-type ci-dessus mesure le bruit genere par le "
      "seul fait\n  de faire varier les tailles. S'il est du meme ordre "
      "que votre resultat,\n  votre historique ne permet pas de conclure, "
      "quel que soit le centile.\n")

if args.graphique:
    try:
        import matplotlib.pyplot as plt
    except ImportError:
        sys.exit("matplotlib n'est pas installe : pip install matplotlib")
    plt.figure(figsize=(9, 5))
    plt.hist(sims, bins=80)
    plt.axvline(reel, linestyle="--", linewidth=2)
    plt.title("Resultat reel vs %d reallocations aleatoires des memes tailles"
              % args.tirages)
    plt.xlabel("Resultat (EUR)")
    plt.ylabel("Nombre de tirages")
    plt.tight_layout()
    plt.show()

if name == "main":
main()
Limites connues

Le script lit le bloc Positions du rapport, donc il raisonne position par position. Si vous travaillez en compte netting plutôt qu'en hedge, ou si vous fermez vos positions par tranches, l'unité d'analyse ne sera pas exactement celle que vous avez en tête.

Le test de permutation suppose que vos trades sont indépendants les uns des autres. Si vous ouvrez plusieurs positions corrélées en même temps, ce qui est le cas de beaucoup d'entre nous, il surestime légèrement la significativité. Autrement dit, le vrai p est probablement un peu moins bon que celui qui s'affiche.

Enfin, un résultat au 99e centile sur 60 trades ne vaut pas grand-chose. C'est la taille de l'échantillon qui commande, comme toujours.

Signalez-moi les bugs, je corrigerai le message.