Nous avions un problème.Notre système de trading automatisé avait une valeur attendue positive: les mathématiques ont été vérifiées, les backtests ont l'air génial, et au début, il a fait de l'argent.Mais au fil du temps, il saignait. Ce n’était pas un bug dans le code, c’était une incompréhension fondamentale de ce qui compte dans la production. Le piège de la valeur attendue La plupart des tutoriels de trading, des documents académiques et des cours en ligne vous enseignent à maximiser la valeur attendue. E[profit] = Σ(probability_i × outcome_i) Si ce nombre est positif, vous devriez prendre le commerce. Si vous pouvez faire ce nombre plus grand, vous devriez optimiser pour cela. À l’exception de la production, cette stratégie d’optimisation présente un défaut fatal : . it doesn't account for the path you take to reach that expected value Laissez-moi vous montrer ce que je veux dire avec un scénario réel de notre système. Le système de saignement Notre stratégie a été conçue pour capturer les pics de prix sur les marchés volatils. Analyser les directions de prix possibles pour chaque fenêtre de trading Optimiser la taille de position en utilisant la programmation quadratique Exécuter des transactions pour capturer les opportunités de spread Sur le papier, la valeur attendue était solidement positive. Jour 1 à 3: Prise d'un gros coup de pouce, faite 15 000 $ Jour 4-12 : Petites pertes tous les jours, total -$8000 Jour 13-14: Un autre coup de pouce, fait 12 000 $ Jour 15-28: saignement progressif, total -11 000 $ Le problème? Notre optimiseur avait développé un biais structurel. Il a systématiquement pris des positions qui gagnent de grandes occasions mais perdent de petites quantités fréquemment. Le calcul de la valeur attendue a dit que cela allait bien: les grandes gains compenseraient finalement. Nous n’avions pas les deux. Voir la différence : une simulation Pour illustrer pourquoi ces contrôles de risque sont importants, comparons deux stratégies de négociation du même marché sur un an: Dimensionnement de position agressif basé uniquement sur la valeur attendue, en utilisant un levier de 150% lorsque les opportunités semblent bonnes. Strategy A (EV Maximization) Les mêmes signaux de marché, mais avec une taille fractionnelle de Kelly (40% d'agressivité) et une réduction de position basée sur le CVaR pendant les périodes de risque de haute queue. Strategy B (Risk-Controlled) Les résultats racontent une histoire cruciale. Regardez de près le graphique de gauche - la plupart des chemins de maximisation EV ne sont pas catastrophiquement échoués. Ils sont juste... pas compounding. Vous pouvez voir le motif de saut: des pics occasionnels, suivis par une érosion lente. Ceci est le saignement insidieux que la valeur attendue positive manque. Notez comment quelques chemins ont atteint 500 000 $? Ces outliers tirent la moyenne jusqu'à 146 000 $. C'est seulement 136 000 $, et 29 sur 100 parcours finissent en dessous du capital de départ. médiane In a backtest, you might have gotten lucky and seen one of those winner paths. In production, you get one random draw. Le bon graphique est « ennuyeux », et c’est exactement le point. Aucun moonshots à 500 000 $, mais aussi aucun tirage au sort catastrophique. La stratégie contrôlée par le risque se regroupe étroitement autour de la croissance modeste. Telle est la réalité de la production : la stratégie qui survit devient complexe.La stratégie qui saigne ne fait rien, peu importe ce que le calcul de la valeur attendue a promis. Ce que la valeur attendue ne capture pas 1 - Risque de ruine C'est le problème du joueur classique, formalisé par le critère Kelly. Même avec une valeur attendue positive, si votre taille de position est erronée, vous Allez vous briser. Will Considérez : vous avez un capital de 100 000 $ et un commerce avec une probabilité de gagner de 60% qui soit double votre pari ou le perd. la valeur attendue est positive (+20%). Kelly vous dit que la taille de mise optimale est: kelly_fraction = (p * b - q) / b # where p = win probability, q = loss probability, b = odds Voici ce que nous avons appris dans la production : . even Kelly is too aggressive Pourquoi ? parce que : Vos estimations de probabilité sont fausses (toujours) Les marchés changent (votre avantage de 60% devient 52%) Les corrélations se brisent pendant le stress (lorsque vous en avez le plus besoin) Vous ne pouvez pas rééquilibrer instantanément (slipage, latence, impact sur le marché) Nous avons fini par utiliser le Kelly fractionnel (25-50% du pari théorique de Kelly) parce que les coûts réels de surestimer votre avantage sont catastrophiques. Instabilité numérique dans les événements extrêmes Un matin, notre système s'est écrasé lors d'un événement météorologique extrême.Non pas un accident de logiciel, mais un accident mathématique. Notre matrice de covariance est devenue singulière.L'optimisateur ne pouvait pas trouver de solution.Nous étions gelés, incapables de négocier, dans les conditions exactes où notre stratégie aurait dû faire le plus d'argent. Le problème: nous avions optimisé pour les scénarios attendus.Mais les événements extrêmes ont des structures de corrélation différentes.Les actifs qui se déplacent normalement indépendamment deviennent soudainement parfaitement corrélés.Votre matrice de covariance soigneusement estimée, construite à partir de milliers de jours normaux, devient inutile. Le calcul de la valeur n'était pas mieux que les calculs prévus. : regularization from sklearn.covariance import LedoitWolf # Instead of sample covariance cov_matrix = np.cov(returns.T) # Use shrinkage towards structured estimator lw = LedoitWolf() cov_matrix_robust = lw.fit(returns).covariance_ Cela élimine une certaine précision dans les temps normaux pour la stabilité dans les extrêmes. Vos calculs de valeur attendue seront légèrement pires. Défaillance de Time Horizon Voici un problème qui n'apparaît pas dans les backtests: votre calcul de la valeur attendue suppose que vous pouvez attendre assez longtemps pour que la loi des grands nombres fonctionne. Dans la production, vous ne pouvez pas. Nous avons découvert cela lorsque notre système a montré une forte valeur attendue positive sur les fenêtres de 90 jours, mais a constamment perdu de l'argent sur les fenêtres de 30 jours. Nos fournisseurs de capital ont examiné les performances mensuelles.Nos limites de risque ont été ajustées trimestriellement en fonction des résultats récents.Si nous avions eu trois mauvais mois, nos limites de position ont été réduites, indépendamment de ce que dit la valeur attendue à long terme. La stratégie théorique a nécessité 6-12 mois pour montrer de manière fiable le profit.La réalité opérationnelle nous a donné 3 mois avant que les conséquences ne commencent. Nous avons dû ajouter des contraintes explicites à l’horizon du temps à notre optimisation : def optimize_with_horizon_constraint(scenarios, max_horizon_days=30): """ Optimize not just for long-term EV, but for probability of positive returns within operational time horizon """ # Standard expected value ev = np.mean(scenarios) # But also: what'sthe probability we're profitable # within our actual time horizon? rolling_returns = pd.Series(scenarios).rolling(max_horizon_days).sum() prob_profitable_in_horizon = (rolling_returns > 0).mean() # Penalize strategies with low short-term win probability # even if long-term EV is great if prob_profitable_in_horizon < 0.6: return ev * 0.5 # Heavily discount return ev Cela signifiait accepter des stratégies dont la valeur théorique attendue était légèrement inférieure, mais avec une probabilité plus élevée de montrer des bénéfices dans nos contraintes opérationnelles. Ce qu’il faut optimiser Après des leçons douloureuses, voici ce que nous avons appris à optimiser pour: Retours ajustés au risque avec CVaR Au lieu de maximiser E[profit], nous minimisons CVaR (valeur conditionnelle à risque): la perte attendue dans les 5% des pires scénarios import cvxpy as cp # Decision variable: position sizes positions = cp.Variable(n_assets) # Scenarios returns scenario_returns = get_price_scenarios() # shape: (n_scenarios, n_assets) portfolio_returns = scenario_returns @ positions # CVaR constraints alpha = 0.05 # 5% tail var = cp.Variable() u = cp.Variable(n_scenarios) constraints = [ u >= 0, u >= -(portfolio_returns - var), ] cvar = var + cp.sum(u) / (n_scenarios * alpha) # Optimize for return while constraining tail risk objective = cp.Maximize(cp.sum(portfolio_returns) / n_scenarios - lambda_risk * cvar) Cela pénalise explicitement les stratégies qui ont de bons rendements moyens mais un risque de queue catastrophique. La robustesse à l'erreur de modèle Nous supposons que notre modèle est faux et optimisons pour Dans un contexte d’incertitude raisonnable : Pire cas # Instead of single expected return estimate mu_estimated = historical_returns.mean() # Assume uncertainty mu_lower_bound = mu_estimated - 2 * historical_returns.std() / np.sqrt(len(historical_returns)) # Optimize for worst-case in uncertainty range # (Robust optimization / minmax approach) Cela protège contre les estimations de paramètres trop fiables. Kelly-Constrainted Position Dimensionnement Nous limitons explicitement les tailles de position en fonction du critère Kelly, même lorsque l'optimisateur veut plus: def kelly_position_limit(edge, volatility, capital, max_kelly_fraction=0.25): """ edge: expected return per unit risk volatility: standard deviation of returns max_kelly_fraction: fraction of theoretical Kelly to actually use """ kelly_full = edge / (volatility ** 2) kelly_fraction = capital * kelly_full * max_kelly_fraction return kelly_position Nous utilisons 25% Kelly comme contrainte.Oui, cela réduit la valeur attendue.Il garantit également que nous continuerons à négocier le mois prochain. L’esprit de production Le passage de la pensée de la valeur attendue à la pensée de la production est philosophique : « Quelle stratégie a le rendement le plus attendu ? » Research mindset « Quelle stratégie survivra si je me trompe sur mes hypothèses ? » Production mindset Voici les changements pratiques que nous avons effectués : Backtests: analyse du mois le plus mauvais ajouté, pas seulement des rendements moyens Taille de position : Conservative par défaut, avec kill-switches pour les anomalies Métriques de risque : suivre CVaR quotidiennement, pas seulement P&L Validation du modèle : Assumer une incertitude de 30 % sur tous les estimations Planification des catastrophes: chemins de code explicites pour les scénarios "modèle est complètement faux" La leçon La valeur attendue est un beau concept mathématique, propre, intuitif et théoriquement optimal. Ce n'est pas suffisant non plus. Dans la production, vous ne négociez pas contre une distribution de probabilité. Vos modèles de risque imparfaits Les marchés qui changent Restrictions opérationnelles qui ne sont pas dans votre backtest La réalité psychologique de regarder votre capital diminuer jour après jour même si la « valeur attendue est positive » Les systèmes qui survivent ne sont pas ceux dont la valeur attendue est la plus élevée.Ce sont ceux qui restent robustes lorsque le modèle est faux, que les marchés changent et que les écureuils noirs apparaissent. Optimiser pour la survie d'abord.Rentabilité second.La valeur attendue est une composante de ce calcul, mais ce n'est pas la fonction objective.