Aller au contenu principal
ingénierieleçons apprisesprogrammation
6 choses que je me dirais avant de construire une plateforme de bots de trading

6 choses que je me dirais avant de construire une plateforme de bots de trading

Ceci clôt une courte série sur la construction de Freya Finance. Plutôt que de répéter les articles, voici ce que je me dirais vraiment au départ, classé selon ce que chaque leçon a coûté à apprendre.

Le fil conducteur est inconfortable : presque aucune de ces défaillances ne s'est annoncée. Elles ont produit des chiffres plausibles, des ordres d'apparence valide, et des écrans qui semblaient corrects. Dans un système qui agit sur l'argent de quelqu'un, le bug qui lève une exception est le gentil.

Points clés

  • Les API tierces échouent en silence. Une réponse HTTP 200 qui transporte moins de données que demandé est le mode de défaillance à anticiper, pas le 500.
  • Testez le simulateur avant de tester quoi que ce soit qu'il simule. Un simulateur défaillant renvoie des chiffres qui ressemblent exactement à ceux d'un simulateur qui fonctionne.
  • Signalez ce que vous n'avez pas pu simuler. Un résultat accompagné d'une lacune déclarée vaut mieux qu'un résultat d'apparence propre qui a discrètement écarté une condition.
  • La précision est un domaine, pas une fonction utilitaire. Les tailles de pas, les tailles de tick et les minimums diffèrent selon la paire, selon l'exchange et selon le type de marché.
  • Choisissez vos contraintes tôt. Décider de ne jamais détenir les fonds des utilisateurs a supprimé toute une catégorie de problèmes au lieu de les résoudre.
  • Dans une interface qui touche à l'argent, auditez les gestes que la plateforme interprète comme des modifications. La molette de la souris au-dessus d'un champ numérique actif en fait partie.

1. Partez du principe que chaque API réussit parfois de manière incorrecte

L'hypothèse qui m'a coûté le plus cher était qu'une requête échouée aurait l'air d'un échec.

Les exchanges sous charge renvoient une réponse HTTP 200 avec moins de bougies que demandé, sans champ d'erreur, sans avertissement. L'un de nos backtests approfondis a demandé environ 536 000 bougies et en a reçu 58 000. La même requête, une heure plus tard, a renvoyé l'ensemble complet. Rien dans la réponse ne distinguait les deux.

Si vous ne vérifiez pas, le moteur simule une stratégie sur une fraction de l'historique prévu et rapporte un chiffre plein d'assurance. C'est pire qu'un crash, car un crash est honnête.

Deux règles en sont ressorties : valider la forme d'une réponse réussie, pas seulement son code de statut, et distinguer les échecs transitoires des échecs permanents avant de décider quoi faire. Ils semblent identiques au moment où ils surviennent et méritent des réponses opposées.

Histoire complète : ce que j'ai sous-estimé

2. Testez le simulateur, pas la stratégie

Tout instinct vous pousse à tester la logique de la stratégie, car c'est la partie intéressante. Le piège, c'est qu'un simulateur défaillant produit un résultat impossible à distinguer de celui d'un simulateur fonctionnel. Une exécution qui a discrètement traité un dixième des données renvoie quand même un chiffre. Une exécution dont les sorties n'ont jamais été évaluées en renvoie un suspicieusement plat.

Le changement qui a résolu cela a consisté à poser des assertions sur des éléments que la stratégie ne peut pas modifier : que les bougies traitées correspondent aux bougies récupérées, qu'une exécution sur une période connue la couvre réellement, qu'une configuration garantie de se déclencher produit des trades.

Quand ces invariants tiennent, un résultat étrange est une vraie découverte. Quand ils ne tiennent pas, le résultat n'est que du bruit déguisé.

3. Signalez ce que vous n'avez pas pu simuler

Celle-ci est un choix de conception plutôt qu'un bug, et je pense que c'est la plus sous-estimée.

Certaines conditions ne peuvent pas être rejouées. Un signal webhook externe n'a aucun historique enregistré. Le réflexe tentant est de l'ignorer et d'évaluer le reste, ce qui fait paraître le résultat complet.

Regardez l'effet sur une stratégie qui exige A ET B. Si B ne peut pas être simulé, A décide seul, donc le bot simulé entre là où le vrai serait resté à l'écart. L'erreur n'est pas aléatoire : écarter une condition sous une logique ET ne peut produire que plus de trades que la réalité, si bien que le biais pointe vers un résultat plus flatteur à chaque fois.

Nous avons continué à lancer la simulation, mais le résultat porte un avertissement explicite qui nomme ce qui a été ignoré. Un simulateur qui ne peut pas échouer bruyamment échouera en silence, et l'échec silencieux dans un système qui produit des chiffres est le pire mode de défaillance qui soit.

Histoire complète : pourquoi les backtests mentent

4. Une courbe de capital lisse est une question, pas une réponse

Point connexe, qui mérite d'être traité à part car il trompe les humains plutôt que le code.

Une grille DCA sans stop loss ne réalise presque jamais de perte. Elle conserve et ajoute. Résultat : les trades clôturés sont presque tous gagnants, le taux de réussite paraît excellent, et la courbe de capital forme un escalier bien net.

Le risque n'a disparu nulle part. Il a été reporté, et ce report a une limite stricte : le capital qu'il reste pour d'autres ordres de sécurité. La bonne question n'est pas « quel a été le drawdown » mais « si le prix continue d'évoluer à contre-courant, à quel moment la stratégie n'a-t-elle plus de marge ? »

Le drawdown lui-même exige le même scepticisme. Il est mesuré par rapport au capital alloué à son sommet, si bien que la même perte de 200 USDT s'affiche à 40 % sur une allocation de 500 USDT et à 4 % sur 5 000. Deux bots qui tradent de façon identique peuvent afficher des chiffres radicalement différents.

Histoire complète : comprendre le drawdown

5. La précision est un domaine, pas un utilitaire

J'avais classé « arrondir les quantités à des pas valides » comme une simple fonction utilitaire. C'est une catégorie de travail entière, et elle se cache dans un endroit où les erreurs coûtent de l'argent.

La virgule flottante en est à l'origine : multiplier 0.29 par un pas de 0.01 donne 28.999999999999996, que l'on arrondit à l'entier inférieur, soit un pas complet trop bas, en silence, vers un ordre plus petit.

Ensuite, les exchanges ne s'accordent même pas sur les règles elles-mêmes. L'un vérifie la valeur de l'ordre en USDT, un autre vérifie le nombre de contrats sans aucune vérification de valeur, un autre vérifie les deux. Notre pire bug dans ce domaine venait de l'invention d'un minimum qu'une plateforme n'impose pas, puis du rejet d'ordres valides à cause de lui. L'indice, avec le recul, était que notre version de la contrainte dépendait du prix alors que la vraie n'en dépendait pas.

Partout où vous inscrivez une constante unique pour quelque chose que l'exchange définit paire par paire, vous écrivez un bug à retardement.

Histoire complète : la virgule flottante va vous coûter de l'argent

6. Choisissez vos contraintes tôt

La dernière n'est pas une erreur. C'est une décision dont j'ai sous-estimé les conséquences, dans le bon sens.

Freya ne détient jamais les fonds de trading des utilisateurs. Les clés portent des permissions de lecture et de trading, jamais de retrait, et une clé qui arrive avec une permission de retrait est refusée plutôt qu'acceptée puis ignorée. Cette distinction compte plus qu'il n'y paraît : « nous ne retirerons pas » est une affirmation sur notre comportement qu'un utilisateur ne peut pas vérifier, alors que « la clé ne peut pas retirer » est imposé par l'exchange et vérifiable par l'utilisateur dans ses propres réglages.

Je m'attendais à ce que ce soit un argument marketing. Cela s'est révélé architectural, et cela a rendu le système plus petit : pas de registre de conservation, pas de réconciliation, pas de file d'attente de retraits, pas de politique de stockage à froid pour le capital de trading. Toute une classe des problèmes les plus difficiles du logiciel financier est absente parce que nous n'avons jamais pris en charge ce qui les crée.

Ce qui la remplace est plus étroit et plus tranchant : le système doit être correct en temps réel, car il ne peut jamais rien annuler. Un ordre exécuté sur le compte d'exchange de quelqu'un d'autre est définitif.

Histoire complète : concevoir un trading non dépositaire

Celle dont je ne pensais pas avoir besoin

Un bonus, car c'est celle qui m'a le plus surpris : dans une interface qui touche à l'argent, le front-end a besoin de la même paranoïa que le moteur.

Un <input type="number"> actif incrémente sa valeur quand vous faites défiler la molette au-dessus. Sur un sélecteur de quantité, c'est un désagrément. Sur le levier, la taille de l'ordre et le prix, cela réécrit silencieusement ce que l'utilisateur a choisi, et le formulaire se valide quand même. Rien dans ce bug n'est visible sur une capture d'écran.

Histoire complète : la molette de la souris modifie vos champs numériques


Si je condensais tout cela en une phrase

Concevez pour les défaillances qui ne s'annoncent pas. Celles qui lèvent une exception vous trouveront d'elles-mêmes.


Lectures complémentaires

Créer un compte

Mettez vos connaissances en pratique et ouvrez un compte Freya dès aujourd'hui.

S'inscrire maintenant
Ce contenu est uniquement à des fins éducatives et ne constitue pas un conseil financier. Le trading de cryptomonnaies comporte des risques significatifs. N'investissez jamais plus que ce que vous pouvez vous permettre de perdre.