Strasmore Research
Apprendre Matt ConnorPar Matt Connor · Mis à jour le 2026-08-04

Coupe-circuits pour robots de trading : gestion du risque

Les coupe-circuits stoppent un robot de trading avant qu'une perte ne s'aggrave. Découvrez la fréquence des pertes quotidiennes de trois pour cent et l'impact du sizing.

Les coupe-circuits pour robots de trading sont des règles qui empêchent une stratégie automatisée d’envoyer des ordres dès qu’une limite définie est atteinte. Ils se situent dans une couche de risque entre la stratégie et le courtier, et ils s’exécutent sur chaque ordre, indépendamment de l’accord de la stratégie. La stratégie décide de ce qu’il faut trader. La couche de risque décide si le trade peut avoir lieu.

0

Cette séparation constitue l’intégralité de la conception. Une stratégie qui s’auto-régule ne dispose d’aucun contrôle indépendant au moment précis où ses propres hypothèses s’effondrent, soit le moment où un contrôle est le plus nécessaire.

Le rôle d’un coupe-circuit dans un robot de trading

Une couche de gestion du risque se compose de quatre éléments, chacun visant à prévenir une défaillance spécifique et banale.

  • Des plafonds stricts sur la taille des positions, l’exposition notionnelle par symbole et la fréquence des ordres. Ils limitent les dommages causés par un bug qui, autrement, entraînerait une perte illimitée.
  • Un coupe-circuit sur drawdown qui suspend l’émission de nouveaux ordres dès que le compte enregistre une perte définie sur la séance, ou une baisse déterminée par rapport à son pic de valeur liquidative.
  • Un dimensionnement dynamique des ordres, calculé à partir de la volatilité récente ou d’une fraction du critère de Kelly plutôt que sur un nombre fixe d’actions. Cela permet de maintenir le risque par trade relativement stable alors que l’amplitude du marché évolue.
  • Un journal d’audit en ajout seul de chaque décision, incluant les ordres rejetés par la couche de risque. C’est le seul élément permettant de distinguer une erreur de stratégie d’une absence d’exécution du contrôle.

Tout ce qui suit détaille concrètement ces quatre points.

Quel est un seuil de perte quotidienne raisonnable pour un robot de trading ?

Une limite de perte quotidienne interrompt l'envoi de nouveaux ordres dès que la perte de la séance dépasse un certain seuil. Le choix de ce chiffre relève du calibrage, pas de la préférence personnelle : s'il est fixé dans la zone du bruit de marché habituel, le robot sera bloqué la plupart des semaines ; s'il est fixé trop loin, il ne se déclenchera jamais. Le point de départ consiste à observer la fréquence à laquelle le marché lui-même enregistre une séance de baisse d'une ampleur donnée.

RequêteJours de baisse du SPY par amplitude, par an, de 2018 à juillet 2026
Le SQL exact derrière chaque chiffre
WITH daily AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           argMax(toFloat64(close), window_start) AS close_px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2017-12-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY d
),
with_prev AS (
    SELECT d,
           close_px,
           any(close_px) OVER (ORDER BY d ASC ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prev_close
    FROM daily
)
SELECT toYear(d) AS year,
       countIf(close_px / prev_close - 1 <= -0.01) AS down_1pct_days,
       countIf(close_px / prev_close - 1 <= -0.02) AS down_2pct_days,
       countIf(close_px / prev_close - 1 <= -0.03) AS down_3pct_days
FROM with_prev
WHERE prev_close > 0
  AND d >= toDate('2018-01-01')
GROUP BY year
ORDER BY year
Run this yourself

Les séances en baisse de un pour cent ou plus ont été au nombre de 15 en 2019 et de 45 en 2020, sur environ deux cent cinquante jours de bourse par an. Le compte des séances en baisse de trois pour cent ou plus est une autre paire de manches : 0 en 2019 contre 16 en 2020. La dernière ligne du 9 ne couvre que les séances jusqu'au trente et un juillet deux mille vingt-six.

La courbe est irrégulière plutôt que stable, et cette irrégularité constitue le point de conception. Les journées difficiles arrivent par grappes. Un robot qui s'arrête le premier jour d'une grappe et reprend le deuxième ne s'est pas réellement arrêté.

Deux seuils remplissent des fonctions différentes. Une limite de perte quotidienne, généralement fixée à deux pour cent des capitaux propres du compte, met fin à la séance. Une limite de drawdown glissant, mesurée par rapport au plus haut historique des capitaux propres et généralement fixée autour de dix pour cent, suspend la stratégie dans l'attente d'une intervention humaine. La première est routinière, la seconde se veut exceptionnelle, et un robot ne disposant que de la première peut éroder un compte par tranches de deux pour cent sans jamais déclencher de protection.

Comment le volatility scaling modifie-t-il la taille des positions ?

Le ciblage de la volatilité ajuste la taille d'une position de manière inverse à la volatilité réalisée récente : lorsque l'amplitude quotidienne double, la position est approximativement divisée par deux, ce qui maintient le risque en dollars par trade à un niveau quasi constant. La volatilité réalisée est ici l'écart-type annualisé des rendements quotidiens, et elle évolue de manière plus marquée que ce que la plupart des intervenants anticipent.

RequêteVolatilité réalisée du SPY par mois et position cible pour une volatilité de 12 %
Le SQL exact derrière chaque chiffre
WITH daily AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           argMax(toFloat64(close), window_start) AS close_px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2023-12-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY d
),
rets AS (
    SELECT d,
           close_px / any(close_px) OVER (ORDER BY d ASC ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) - 1 AS ret
    FROM daily
)
SELECT formatDateTime(toStartOfMonth(d), '%Y-%m') AS month,
       round(stddevSamp(ret) * sqrt(252) * 100, 1) AS realized_vol_pct,
       round(least(100.0, 1200.0 / (stddevSamp(ret) * sqrt(252) * 100)), 1) AS vol_target_size_pct
FROM rets
WHERE d >= toDate('2024-01-01')
  AND isFinite(ret)
GROUP BY toStartOfMonth(d)
HAVING count() >= 15
ORDER BY toStartOfMonth(d)
Run this yourself

La volatilité réalisée mesurée 11.1% annualisée en 2024-01 et 12% en 2026-07, sur 31 mois. La seconde colonne convertit chaque lecture en la position qu'une cible de volatilité de douze pour cent impliquerait, plafonnée à la ligne complète : 100% en 2024-01 contre 99.7% en 2026-07. Même stratégie, même conviction, mais un nombre d'actions très différent.

Le critère de Kelly aborde le même problème sous un angle opposé, en dimensionnant la position à partir de l'avantage estimé et de la variance plutôt que de la seule volatilité. La plupart des opérateurs systématiques en utilisent une fraction, la moitié ou le quart du Kelly, étant donné que ces deux paramètres sont des estimations basées sur un échantillon fini. Dimensionnement de position selon le critère de Kelly détaille ce calcul.

Pourquoi un robot de trading réintègre-t-il systématiquement après un stop ?

Un stop est déclenché. La position est clôturée. Quatre-vingt-dix secondes plus tard, la condition d'entrée est à nouveau remplie, le robot se repositionne, subit la même perte, et recommence. Aucun composant n'est défaillant. La stratégie a exécuté ses instructions, le stop a fonctionné comme prévu, et le compte continue de s'éroder, un aller-retour à la fois.

La fréquence découle directement de la trajectoire des prix. Ce panneau comptabilise, par séance, combien de fois le SPY est passé de plus de 0,1 % au-dessus de son cours d'ouverture à plus de 0,1 % en dessous, ou inversement.

RequêteFréquence de croisement du prix d'ouverture du SPY, par séance et par mois
Le SQL exact derrière chaque chiffre
WITH mins AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           window_start AS ts,
           toFloat64(close) AS px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2025-08-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
),
opens AS (
    SELECT d, argMin(px, ts) AS open_px
    FROM mins
    GROUP BY d
),
zoned AS (
    SELECT m.d AS d,
           m.ts AS ts,
           multiIf(m.px >= o.open_px * 1.001, 1,
                   m.px <= o.open_px * 0.999, -1,
                   0) AS zone
    FROM mins AS m
    INNER JOIN opens AS o ON m.d = o.d
),
flips AS (
    SELECT d,
           zone,
           any(zone) OVER (PARTITION BY d ORDER BY ts ASC ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prev_zone
    FROM zoned
    WHERE zone != 0
),
per_day AS (
    SELECT d, countIf(prev_zone != 0 AND zone != prev_zone) AS crossings
    FROM flips
    GROUP BY d
)
SELECT formatDateTime(toStartOfMonth(d), '%Y-%m') AS month,
       round(avg(crossings), 1) AS avg_crossings_per_session,
       max(crossings) AS max_crossings_in_a_session
FROM per_day
GROUP BY toStartOfMonth(d)
ORDER BY toStartOfMonth(d)
Run this yourself

Le SPY a franchi cette bande en moyenne 0.7 fois par séance en 2025-08 et 1.5 fois en 2026-07, avec une séance en 2026-07 enregistrant 5 franchissements. Toute règle qui ouvre une position d'un côté d'un niveau et déclenche un stop de l'autre a autant d'occasions de s'exécuter au cours d'une seule journée.

Quatre mécanismes permettent de limiter ce phénomène.

  • Un délai de refroidissement après chaque stop, mesuré en minutes ou en barres, durant lequel aucun nouvel ordre pour ce symbole ne franchit la couche de risque.
  • Un plafond quotidien de transactions par symbole, qui transforme une boucle illimitée en une boucle bornée.
  • Un indicateur d'arrêt qui se verrouille. Une fois la limite de perte quotidienne atteinte, il reste actif jusqu'à ce qu'un opérateur le réinitialise.
  • La persistance de cet indicateur en dehors de la mémoire du processus. Un superviseur qui redémarre un robot après un plantage lui offre une ardoise propre, alors que cet indicateur a précisément pour but d'empêcher une telle remise à zéro.

Le dernier point concerne ceux qui ont pourtant tout fait correctement. Les robots de grid trading placent des échelles d'ordres par conception, ce qui rend le plafond de transactions structurel plutôt que décoratif.

Que se passe-t-il lorsqu’un bot traite sur un flux de prix obsolète ?

Une cotation qui n’est plus actualisée ressemble toujours à un chiffre. Le bot le lit, valorise un ordre en fonction, et envoie cet ordre sur un marché qui a évolué. L’échec est silencieux : aucune exception n’est levée, aucune erreur n’est consignée, et les exécutions ne semblent anormales qu’a posteriori.

La version mesurable de manière précise est le gap de nuit, où un prix connu reste inchangé pendant des heures alors que le prix négociable évolue.

RequêteGap overnight (clôture à ouverture) : six tickers, de janv. 2024 à juil. 2026
Le SQL exact derrière chaque chiffre
WITH daily AS (
    SELECT ticker,
           toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           argMin(toFloat64(open), window_start) AS open_px,
           argMax(toFloat64(close), window_start) AS close_px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('SPY', 'KO', 'MSFT', 'AAPL', 'NVDA', 'TSLA')
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2024-01-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY ticker, d
),
gaps AS (
    SELECT ticker,
           d,
           open_px,
           any(close_px) OVER (PARTITION BY ticker ORDER BY d ASC ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prev_close
    FROM daily
)
SELECT ticker,
       round(quantileDeterministic(0.5)(abs(open_px / prev_close - 1) * 100, cityHash64(ticker, d)), 2) AS median_gap_pct,
       round(quantileDeterministic(0.95)(abs(open_px / prev_close - 1) * 100, cityHash64(ticker, d)), 2) AS p95_gap_pct,
       round(max(abs(open_px / prev_close - 1) * 100), 2) AS max_gap_pct
FROM gaps
WHERE prev_close > 0
GROUP BY ticker
ORDER BY p95_gap_pct DESC
Run this yourself

Le titre présentant le gap le plus large au 95e percentile était TSLA à 4.41%, contre 1% pour KO. Les nuits habituelles étaient bien plus calmes : des gaps médians de 1.01% et 0.24% respectivement. Les queues de distribution justifient la mise en place d’une couche de risque, et le plus grand gap unique sur TSLA durant la période observée a atteint 14.57%. Ce sont les écarts auxquels s’expose un bot agissant sur un prix lu il y a quelque temps. Pourquoi les actions présentent des gaps overnight détaille les mécanismes à l’œuvre.

Les défenses sont peu coûteuses. Appliquez une limite d’âge maximale à chaque cotation utilisée par la couche de risque pour la valorisation, généralement quelques secondes pour une stratégie intraday. Utilisez un signal de « heartbeat » distinct des données pour le flux, ce qui permet de distinguer une socket silencieuse d’un marché atone. Considérez l’absence de données comme une suspension plutôt que comme un maintien, car un bot sans prix ne peut pas non plus évaluer ses sorties.

Quels plafonds stricts intégrer à la couche de risque ?

  • Notional maximum par symbole en pourcentage des fonds propres du compte. Un plafond de dix pour cent empêche un seul symbole défaillant de compromettre l'ensemble du compte.
  • Notional brut maximum sur l'ensemble des positions ouvertes. Le fixer à cent pour cent des fonds propres signifie l'absence de levier, une décision qu'il vaut mieux prendre explicitement plutôt que de subir les paramètres par défaut du courtier.
  • Cadence maximale d'ordres, par minute et par jour. Dix ordres par minute est une limite généreuse pour la plupart des stratégies de détail, tout en limitant une boucle incontrôlée à l'échelle d'une minute.
  • Taille maximale d'ordre en pourcentage du volume quotidien moyen du symbole. Un plafond de un pour cent est la limite qui empêche un bot de faire bouger le cours sur lequel il tente d'exécuter ses ordres, et le volume quotidien moyen en constitue le dénominateur.

Chacune de ces limites doit figurer dans la couche de risque plutôt que dans la stratégie, et chacune emprunte le même cheminement de code en backtest, en paper trading et en conditions réelles. Une limite qui n'existe qu'en production est une limite que personne n'a testée.

Que doit contenir un journal d’audit de bot de trading ?

Un journal en mode « append-only » enregistre une ligne par décision, sans modification ni suppression possible. Chaque enregistrement contient l'horodatage, la cotation utilisée et son ancienneté, chaque contrôle de limite effectué avec son verdict, l'ordre envoyé et la réponse du courtier. Les ordres rejetés sont consignés avec la même importance que les ordres exécutés.

L'objectif est la reconstruction. Six semaines après une mauvaise séance, la question n'est jamais de savoir quel était le P&L. Il s'agit de déterminer quel contrôle a été validé, sur la base de quelles données d'entrée. Sans l'enregistrement des données d'entrée, vous finissez par déduire l'état du bot à partir de celui du marché, ce qui revient à commettre la même erreur que le biais d'anticipation dans le backtesting : utiliser des informations que le système ne possédait pas au moment de la décision.

Le projet riskguard est une implémentation open-source de cette séparation, où les contrôles de limites résident dans un composant appelé par la stratégie plutôt que dans une logique dispersée au sein de la stratégie elle-même. C'est une conception parmi d'autres, qu'il convient d'étudier plutôt que d'adopter aveuglément. Quelle que soit votre dépendance, fixez une version taguée plutôt qu'une branche par défaut. Une branche peut changer entre deux exécutions du même backtest, et une couche de risque qui a été modifiée silencieusement est pire que l'absence totale de contrôle.

Pourquoi un premier déploiement s'effectue sur un compte de démonstration

L'adaptateur de courtage est configuré par défaut sur le mode « paper trading », le passage au trading réel nécessitant l'activation explicite d'un paramètre dédié. La défaillance évitée est triviale : un fichier de configuration copié ou une variable d'environnement non mise à jour qui entraînerait l'envoi d'ordres réels avec des capitaux réels.

Une exécution en mode « paper » génère également l'artefact essentiel : un journal de décisions issu de la même couche de risque, basé sur des prix réels, indiquant quels seuils ont été déclenchés et lesquels ne l'ont pas été. Il s'agit d'une preuve concernant la couche de risque, une question distincte de la rentabilité de la stratégie. Le paper trading avant l'engagement de capitaux réels détaille ce qu'un historique de « paper trading » prouve ou ne prouve pas, et les systèmes de trading multi-agents basés sur l'IA démontre pourquoi l'autorité d'interruption doit être située en dehors de chaque agent dès lors que plusieurs d'entre eux sont en mesure de passer des ordres.

FAQ sur les coupe-circuits des bots de trading

Qu'est-ce qu'un coupe-circuit dans un bot de trading ?

Il s'agit d'une règle intégrée à la couche de risque qui empêche le bot d'envoyer de nouveaux ordres une fois qu'une limite définie est atteinte, le plus souvent un seuil de perte quotidienne ou un drawdown par rapport au pic de capital du compte. Ce mécanisme fonctionne indépendamment de la stratégie, s'applique à chaque ordre et reste actif jusqu'à ce qu'une intervention le réinitialise.

À quelle fréquence le marché enregistre-t-il une baisse de deux pour cent ?

Le SPY a enregistré 5 séances avec une baisse de deux pour cent ou plus en 2019 et 25 en 2020, sur environ deux cent cinquante jours de bourse par an. Cet écart entre une année calme et une année sous tension explique pourquoi une limite de perte doit être calibrée sur l'historique plutôt que sur l'intuition.

Comment empêcher un bot de reprendre ses activités après un arrêt ?

Une fenêtre de refroidissement après chaque arrêt et un plafond de transactions quotidiennes par symbole transforment une boucle illimitée en une boucle bornée. Le signal d'arrêt doit également être verrouillé et persister en dehors de la mémoire vive, faute de quoi un superviseur redémarrant un bot planté lui fournirait un état neuf, sans aucune restriction.

Comment un bot peut-il détecter qu'un flux de prix est obsolète ?

En vérifiant l'ancienneté de chaque cotation avant de valoriser un ordre, et en surveillant un signal de pulsation (« heartbeat ») du flux indépendamment des données. Les écarts de cours durant la nuit illustrent l'ampleur de ce qu'un prix obsolète peut masquer : le quatre-vingt-quinzième centile des mouvements nocturnes a atteint 4.41% le TSLA entre janvier 2024 et juillet 2026.

Un petit bot de trading a-t-il vraiment besoin d'un journal d'audit ?

Un journal des exécutions enregistre ce qui s'est passé. Un journal des décisions enregistre ce que le bot pensait être autorisé à faire ; c'est le seul moyen de distinguer une stratégie défaillante d'un contrôle de risque qui ne s'est jamais déclenché. Un journal en mode ajout seul (« append-only »), incluant les rejets, constitue la version minimale utile.


Chaque chiffre ci-dessus provient d'une requête stockée sur des barres d'une minute, et chaque panneau s'ouvre sur le SQL correspondant. Appliquez ces mêmes requêtes à votre propre liste de symboles sur le terminal Strasmore.

#risk-management#trading-bots#drawdown#position-sizing#automation