Les ordres bracket (OSO/OCO) de l'API Tradovate échouent
Votre entrée s'exécute sur ES ou NQ et le stop-loss ou le take-profit n'apparaît jamais. Voici ce que signifient réellement le 200 OK, le 404 et le rejet 'Wrong OCO combination', et comment corriger chacun d'eux.
Votre automatisation envoie un ordre bracket de l'API Tradovate, l'entrée est exécutée sur ES ou NQ, puis… rien. Pas de stop-loss, pas de take-profit. Vous êtes désormais à un mauvais tick d'une position non protégée, et votre journal indique que l'ordre a été “envoyé avec succès”. C'est le piège. En 2026, l'échec classique n'est plus un écran d'erreur rouge, mais un statut HTTP 200 OK qui cache un failureReason et un failureText dans le corps, ou un appel orderStrategy qui revient sous forme d'un simple 404. Les variantes les plus fréquentes : un 404 (undocumented) venant de startOrderStrategy, une erreur d'analyse Invalid JSON, un rejet Wrong OCO combination, et la plus sournoise, une exécution partielle silencieuse où seule l'entrée survit. Voici ce que chaque erreur signifie réellement, comment corriger les problèmes d'endpoint et de champs qui les causent, et comment PickMyTrade empêche une exécution non protégée d'atteindre jamais votre compte.
Check-list rapide pour les ordres bracket (OSO/OCO) en échec
- Lisez le corps de la réponse, pas seulement le code HTTP. Tradovate vous renvoie
200 OKmême quand l'ordre est mort-né. La vérité se trouve dansfailureReason/failureText. - Vérifiez l'endpoint. Utilisez
order/placeOSOpour une entrée qui envoie des jambes stop/cible,order/placeOCOpour deux sorties liées, etorderStrategy/startOrderStrategypour un bracket côté serveur. - Envoyez les deux champs de compte. Vous avez besoin de l'
accountIdnumérique (issu deaccount/list) et du nom de compteaccountSpec. Si l'un manque, ou s'ils ne correspondent pas, vous obtenezAccess is denied. - Sérialisez du vrai JSON. Envoyez un corps JSON (
json=en Pythonrequests), pas un dict brut, sinon c'estInvalid JSON: expected '{'. - Utilisez
orderStrategyTypeId: 2. C'est la seule valeur valide. Un1vous vaut un404 (undocumented). - Gardez un repli prêt. Si l'endpoint de stratégie continue d'échouer, placez l'entrée, puis attachez un
placeOCOstop/cible dès que vous détenez la position.
Ce que signifient « Wrong OCO Combination » et les erreurs 404
Tradovate vous offre plusieurs façons de soumettre des ordres protégés, et chacune échoue à sa manière. Un bracket est un ordre d'entrée plus deux jambes enfants, un stop protecteur et un objectif de profit, où l'exécution ou l'annulation de l'une annule l'autre. Sur l'API REST, vous le construisez avec order/placeOSO (One-Sends-Other) : un ordre parent porte des objets bracket1 et bracket2 qui ne s'activent qu'après l'exécution du parent. order/placeOCO (One-Cancels-Other) lie deux ordres pour que l'exécution de l'un annule l'autre, pratique pour attacher un stop et un objectif à une position que vous détenez déjà.
Ce qui prête à confusion : ces endpoints renvoient allègrement 200 OK tout en rejetant quand même l'ordre. Tradovate signale les échecs de logique métier dans le corps de la réponse, pas dans le statut HTTP. Ainsi, un payload qui atteint le serveur proprement peut malgré tout revenir avec {"failureReason": "InvalidPrice", "failureText": "Wrong OCO combination"}, ce qui signifie que les niveaux de prix ou l'appariement de types d'ordre choisis ne forment pas un OCO valide. Un stop et une limite situés du mauvais côté du marché suffisent à le provoquer. Traitez tout corps contenant failureReason comme un rejet, point final, quoi que dise la ligne de statut.
L'endpoint orderStrategy/startOrderStrategy est une autre bête. Il exécute une stratégie bracket côté serveur, l'équivalent API d'une stratégie ATM, et il est bien plus exigeant sur son payload. Envoyez le mauvais orderStrategyTypeId, ou appelez-le en REST simple alors qu'il attend une frame WebSocket, et vous obtenez un 404 (undocumented) peu utile. Cela ressemble à une route manquante, mais c'est en réalité une requête rejetée.
Principales causes d'échec des ordres bracket de l'API Tradovate
1. Vous n'avez vérifié que le statut HTTP, pas le corps
C'est le piège numéro un. Votre client voit 200 OK, consigne “ordre envoyé” et passe à autre chose, alors que l'entrée a été rejetée, ou que seul l'ordre parent est passé. Analysez chaque réponse OSO/OCO à la recherche de failureReason et failureText avant de considérer le bracket comme actif.
2. orderStrategyTypeId incorrect sur startOrderStrategy
Beaucoup essaient orderStrategyTypeId: 1 et n'obtiennent pour leur peine qu'un 404 (undocumented). Il n'existe qu'une seule valeur valide, et c'est 2. Tout le reste est rejeté avant même que la stratégie soit construite.

3. Appel de startOrderStrategy en REST au lieu de WebSocket
Même avec le bon id de type, cet endpoint n'est pas fiable en HTTP REST simple. Il est conçu pour fonctionner via un WebSocket, et il fonctionne de manière fiable lorsqu'il est piloté ainsi. Un appel REST qui échoue sans cesse en 404 réussit souvent, sans aucun changement, dès que vous l'envoyez sous forme de frame WebSocket.
4. JSON malformé ou dict brut au lieu d'un corps JSON
Un échec courant de placeOCO est Invalid JSON: expected '{', offset: 0x00000075. Cela se produit lorsque la requête envoie un dictionnaire encodé en formulaire au lieu d'une chaîne JSON sérialisée, en Python, en passant data=payload au lieu de json=payload (ou en oubliant json.dumps()). Le serveur ne voit jamais de JSON valide, donc il rejette tout le bracket.
5. accountSpec manquant, accountId erroné, ou combinaison de prix illégale
Les endpoints de bracket exigent à la fois l'accountId numérique (extrait de account/list) et la chaîne accountSpec (le nom de votre compte). Omettez l'un ou l'autre et vous obtenez Access is denied. Par ailleurs, placeOCO et placeOSO vérifient que les deux jambes forment une combinaison légale, un stop et une limite au prix situé du mauvais côté du marché reviennent sous la forme Wrong OCO combination. Les brackets à entrée Market ajoutent une complication supplémentaire : comme l'API a besoin de niveaux de prix concrets pour les jambes enfants, vous ne pouvez généralement pas attacher un TP/SL relatif en ticks à une entrée Market simple via placeOSO. Vous calculez vous-même les niveaux de prix, ou vous laissez le moteur de stratégie gérer les décalages.
Comment corriger les ordres bracket de l'API Tradovate : étape par étape
Corriger le piège « 200 OK mais pas de jambes »
- Après chaque appel
placeOSO/placeOCO/startOrderStrategy, analysez le corps JSON. - Vérifiez la présence d'une clé
failureReason. Si elle est présente, traitez l'ordre comme rejeté et lisezfailureTextpour en connaître la cause. - Ne marquez le bracket comme actif qu'une fois que vous disposez des IDs d'ordre confirmés pour le parent et les deux jambes enfants, interrogez
order/listou abonnez-vous aux événements d'ordre via WebSocket. - Consignez le corps complet, pas seulement le code de statut, afin que les exécutions partielles apparaissent dans votre piste d'audit.
Corriger les 404 de startOrderStrategy
- Réglez
orderStrategyTypeIdsur2, la seule valeur acceptée. - Envoyez à la fois
accountIdetaccountSpec, plussymbol,action, et l'objetparams(avec votreentryVersionet vosbrackets). - Soumettez la requête sous forme de frame WebSocket plutôt qu'un POST REST. Cet endpoint est conçu pour fonctionner via WebSocket, et le format de frame attendu est bien documenté.
- Réessayez le même payload via le socket avant de supposer que votre JSON est cassé, le 404 est généralement dû au transport, pas au schéma.

Corriger Invalid JSON et Wrong OCO combination
- Sérialisez le payload en JSON. En Python
requests, utilisezrequests.post(url, headers=..., json=payload), jamaisdata=payloadavec un dict. - Vérifiez que l'en-tête
Content-Type: application/jsonest bien défini. - Pour
placeOCO, vérifiez la géométrie des deux jambes : le stop et la limite doivent se situer de part et d'autre, du bon côté valide du prix actuel selon le sens de la position. Si vous voyezWrong OCO combination, inversez la jambe du mauvais côté. - Pour une entrée
Market, attendez l'exécution et attachez un stop/objectifplaceOCOà la position résultante, ou passez àstartOrderStrategy, qui accepte des décalages relatifs.
Le repli fiable : entrée séparée + OCO
Lorsqu'un bracket natif refuse tout simplement de coopérer, dissociez l'entrée des sorties. Placez l'ordre d'entrée seul avec order/placeOrder, confirmez l'exécution, puis soumettez un placeOCO qui associe le stop protecteur à l'objectif de profit sur la position désormais ouverte. C'est un aller-retour supplémentaire, mais cela contourne entièrement l'endpoint de stratégie et vous donne un contrôle explicite sur chaque jambe.

Tableau de dépannage
| Erreur | Signification | Correction |
|---|---|---|
| 200 OK avec failureReason dans le corps | Ordre rejeté au niveau métier malgré un statut HTTP propre | Analysez le corps ; ne faites jamais confiance au seul code de statut |
| 404 (undocumented) sur startOrderStrategy | orderStrategyTypeId incorrect, ou REST utilisé alors que WebSocket est attendu | Réglez orderStrategyTypeId: 2 et envoyez via WebSocket |
| Invalid JSON: expected '{', offset: 0x... | Un dict brut / corps de formulaire a été envoyé au lieu de JSON sérialisé | Envoyez un corps JSON (json= dans requests) ou appliquez d'abord json.dumps() |
| failureReason: InvalidPrice, failureText: Wrong OCO combination | Les deux jambes OCO ne forment pas un appariement prix/type valide | Repositionnez les prix pour que le stop et la limite soient du bon côté opposé |
| Access is denied | accountId ou accountSpec manquant ou incorrect | Envoyez l'accountId numérique issu de account/list ainsi que le nom accountSpec |
| L'entrée s'exécute, aucun stop/objectif n'apparaît | Jambes enfants rejetées silencieusement alors que le parent a été accepté | Confirmez les trois IDs d'ordre, ou repliez-vous sur entrée + placeOCO |
Comment PickMyTrade évite ce problème
Construire à la main des payloads OSO/OCO signifie assumer chacun des modes d'échec ci-dessus. PickMyTrade se place entre vos alertes TradingView et Tradovate et gère la plomberie du bracket à votre place :
- Gestion des brackets et OCO, attache correctement les jambes stop-loss et take-profit, afin qu'une entrée ne reste jamais sans protection.
- Validation des réponses, examine la réponse complète de l'ordre, pas seulement le statut HTTP, et fait remonter les vrais rejets au lieu d'un faux “succès”.
- Filtres d'habilitation et de risque, respecte l'état de l'accord de données de votre compte et les limites de la prop firm avant qu'un ordre soit acheminé.
- Routage sécurisé face aux limites de débit, espace le flux d'ordres pour que les jambes du bracket ne se heurtent pas aux plafonds de requêtes.
- Synchronisation multi-comptes, réplique le même bracket protégé sur chaque compte connecté.
Tradez sans rejets
Démarrez votre essai gratuit de 5 jours, connectez vos alertes dès aujourd'hui et laissez PickMyTrade attacher correctement le stop-loss et le take-profit à chaque fois.
Démarrez votre essai gratuit de 5 joursQuestions fréquentes
Utilisez order/placeOSO lorsqu'une seule entrée doit envoyer un stop et un objectif en tant que bracket1 et bracket2. Utilisez order/placeOCO pour lier deux ordres de sortie de sorte que l'exécution de l'un annule l'autre. Utilisez orderStrategy/startOrderStrategy pour une stratégie bracket côté serveur avec des décalages relatifs.
Tradovate signale les rejets de logique métier dans le corps de la réponse, pas dans le statut HTTP. Analysez le corps à la recherche de failureReason et failureText, et ne considérez le bracket comme actif qu'une fois que vous avez les IDs d'ordre confirmés pour le parent et les deux jambes enfants.
C'est un rejet InvalidPrice signifiant que vos deux jambes OCO ne forment pas un appariement légal, généralement le stop et la limite sont au prix du mauvais côté du marché pour le sens de la position. Repositionnez le prix de la jambe fautive.
Presque toujours un orderStrategyTypeId incorrect (il doit être 2) ou un appel REST alors que Tradovate attend une frame WebSocket. Corrigez l'id de type et renvoyez via le WebSocket.
Vous envoyez un dictionnaire brut ou un corps encodé en formulaire. Sérialisez d'abord le payload en JSON, en Python requests, passez json=payload au lieu de data=payload.
Pas directement, placeOSO attend des niveaux de prix concrets pour ses jambes enfants. Calculez vous-même les prix exacts avant l'envoi, attendez l'exécution puis attachez un placeOCO, ou utilisez startOrderStrategy, qui accepte des décalages relatifs.
Dissociez le flux. Placez l'entrée avec order/placeOrder, confirmez l'exécution, puis soumettez un placeOCO qui associe le stop et l'objectif à la position ouverte. Cela évite entièrement l'endpoint de stratégie.
Oui. Les endpoints de bracket attendent l'accountId numérique issu de account/list et le nom de compte accountSpec sous forme de chaîne. Omettre l'un ou l'autre renvoie Access is denied.
Ce guide est fourni à des fins éducatives et informatives uniquement et ne constitue pas un conseil financier, d'investissement ou de trading. Le trading de futures et d'autres produits à effet de levier comporte un risque de perte substantiel et ne convient pas à tous les investisseurs. PickMyTrade est une plateforme d'automatisation tierce indépendante et n'est ni affiliée, ni approuvée, ni sponsorisée par Tradovate, Inc. ou Bookmap. Tous les noms, logos et marques associés sont la propriété de leurs détenteurs respectifs. Les fonctionnalités et les étapes de la plateforme évoluent avec le temps, veuillez donc toujours vérifier le processus actuel dans la documentation officielle de la plateforme avant d'agir.