Découper un moteur de trading pour le rendre testable
Je développe un bot de trading pour Hyperliquid. Ce bot gère des positions sur plusieurs paires de cryptomonnaies, à partir de treize règles de scoring. Avec le temps, le code est devenu difficile à maintenir et à tester, surtout pour les parties critiques comme la gestion des positions et les règles de trading.
Découpage du moteur en modules
Pour résoudre ce problème, j’ai décidé de découper le moteur en modules plus petits et plus spécifiques. L’objectif était de rendre chaque partie du code plus lisible, testable et facile à maintenir.
Le premier module extrait était celui des règles de scoring. Ces règles évaluent les conditions du marché pour décider si une position doit être ouverte, maintenue ou fermée. Elles étaient mélangées dans une fonction de 470 lignes, ce qui les rendait difficiles à comprendre et à tester.
J’ai créé un nouveau fichier strategy/scoring_rules.py pour isoler ces règles. Chaque règle est désormais une fonction pure qui prend un contexte en entrée et retourne des points ainsi qu’un texte de debug. Cela permet de tester chaque règle indépendamment et de voir comment elles contribuent au score final.
Module de gestion des positions ouvertes
Un autre module critique était celui de la gestion des positions ouvertes. Les règles de trailing stop, breakeven et clôture par l’exchange étaient mélangées avec le démarrage du bot et la boucle principale. Cela rendait difficile la compréhension de leur fonctionnement ainsi que les tests isolés.
J’ai extrait ces règles dans un nouveau fichier trader/position_rules.py. Chaque décision est maintenant une fonction pure qui ne connaît pas l’exchange et ne modifie rien. Cela permet de tester ces règles dans les deux sens, à la hausse comme à la baisse, sans besoin d’un environnement de trading réel.
Gestion des appels HTTP externes
Un autre problème concernait la gestion des appels HTTP externes. En cas d’échec de résolution DNS ou de coupure réseau, le bot perdait des cycles entiers de collecte de données. Cela pouvait entraîner des décisions de trading basées sur des informations incomplètes ou obsolètes.
Pour résoudre ce problème, j’ai ajouté un système de réessai HTTP dans utils/http.py. Ce module gère maintenant les erreurs de connexion, les dépassements de délai et les erreurs de résolution DNS. Cela permet au bot de continuer à fonctionner même en cas de problèmes réseau temporaires.
J’ai également ajouté une redondance DNS pour éviter les pertes de cycles en cas d’échec de résolution. Cela permet au bot de passer à une autre adresse DNS si la première échoue, sans perdre de temps précieux.
Module de notification
Un autre module critique était le notifier, qui envoie des alertes en cas de problème. En cas d’échec temporaire, comme un 429 de Telegram ou une coupure réseau, l’alerte était perdue définitivement. Cela rendait difficile la réaction rapide aux problèmes.
Pour résoudre ce problème, j’ai ajouté un système de réessai HTTP dans utils/notifier.py. Cela permet au notifier de retenter l’envoi de l’alerte en cas d’échec temporaire, sans perdre l’information critique.
Surveillance externe
Enfin, j’ai ajouté un watchdog externe pour surveiller la santé du bot. Le 22 août, le bot est mort sans que personne ne soit prévenu, car le watchdog vivait sur une machine retirée du réseau. Cela a entraîné 14 jours de collecte arrêtée.
Le watchdog externe lit maintenant les états de santé du bot dans Atlas toutes les 5 minutes et envoie une alerte Telegram en cas de problème. Cela permet de réagir rapidement aux problèmes de santé du bot, même si la machine qui l’héberge est indisponible.
Conclusion
Ces changements ont rendu le code du bot plus lisible, testable et maintenable. Chaque module est maintenant responsable d’une partie spécifique du fonctionnement du bot, ce qui facilite la compréhension et le débogage.
Les tests unitaires sont maintenant plus efficaces, car ils peuvent être écrits pour chaque module en isolation. Cela permet de détecter et de corriger les erreurs plus rapidement, avant qu’elles ne causent des problèmes en production.
Enfin, ces changements ont amélioré la robustesse du bot face aux problèmes réseau temporaires. Les réessais HTTP et la redondance DNS permettent au bot de continuer à fonctionner même en cas de coupure réseau ou d’échec de résolution DNS.
Ces améliorations ont rendu le bot plus fiable et plus facile à maintenir, ce qui est crucial pour un projet de trading en ligne.
Un autre avantage de cette restructuration est la possibilité d’ajouter de nouvelles fonctionnalités plus facilement. Chaque module est maintenant bien défini et isolé, ce qui facilite l’ajout de nouvelles règles ou de nouveaux comportements sans affecter le reste du code.
Par exemple, j’ai activé une règle de scoring inerte depuis l’origine, qui n’avait jamais contribué au score. Elle compte désormais ; son effet sur les décisions reste à mesurer.