Projet B · Artefact open-source · Moteur + article rédigés
Quant Research Framework
Un framework de trading systématique de qualité recherche que n’importe qui peut utiliser pour générer des stratégies, à base de règles ou de ML, avec une walk-forward optimisation à toute épreuve, un optimiseur de lookback intégré qui tourne par régime, un segmenteur de régime personnalisable, et une suite de robustesse à 5 scénarios. Livré comme une référence Python et un port Rust équivalent à la spécification tenu à un contrat de parité numérique publié à chaque PR.
Deux moteurs, une spécification
Pas un wrapper Python autour de Rust, deux implémentations indépendantes du même backtester
Un schéma courant dans l’outillage quant est une façade Python par-dessus une boucle chaude Rust. Ce framework est autre chose : deux moteurs complets et autonomes, un en Python, un en Rust, qui implémentent indépendamment la même spécification algorithmique et sont tenus à une sortie numérique identique par un protocole de parité qui tourne à chaque PR.
Choisissez le langage qui correspond à votre stack. Si vous vivez dans pandas, numpy, scikit-learn et les notebooks, installez la référence Python (pip install quant-research-framework) et vous avez un moteur de recherche complet, contrat de stratégie, walk-forward, régime, suite de robustesse, registre de métriques, diagnostics Monte Carlo et Deflated-Sharpe, tournant nativement en Python, avec une compilation JIT numba à l’intérieur de la boucle d’exécution des trades.
Si vous livrez en production, voulez un binaire statique unique, ou tournez à l’intérieur d’une stack de trading Rust, installez le port Rust (cargo add quant-research-framework-rs). Ce n’est pas une liaison Python : c’est une ré-implémentation indépendante de la même spécification avec un chemin de données Vec<Bar> et un contrat de stratégie natif Rust fn(&[Bar], usize) → Vec<i8>.
Les deux moteurs calculent leur échelle d’indicateurs en double précision IEEE 754. Dispositions mémoire différentes, régimes d’arrondi différents (LLVM-via-rustc vs LLVM-via-numba), RNG différents. Le fait qu’ils produisent des métriques imprimées identiques sur 210 points vérifiés à une tolérance relative ≤10⁻³, avec une déviation observée au pire cas de 5×10⁻⁵, est exactement ce que le protocole de parité existe pour démontrer. Un bug dans une implémentation doit soit correspondre à un bug équivalent dans l’autre, soit être attrapé.
Ce qui le distingue
Ce que ce framework réussit là où les autres backtesters échouent
Chaque composant de ce framework existe quelque part dans l’écosystème open-source. La contribution est la combinaison, et la discipline qui tient la combinaison ensemble. Le tableau ci-dessous résume une étude que nous avons menée de six backtesters largement utilisés en avril 2026 selon les quatre axes qui comptent le plus pour un travail de qualité recherche.
Walk-forward optimisation intégrée, sélection de lookback par régime, no-look-ahead strict imposé par des tests de propriété automatisés au niveau du registre de trades, et tests de parité octet-à-octet inter-langages, cette combinaison est, à notre connaissance, unique à ce framework. Chaque axe individuel est implémenté quelque part ; QuantConnect Lean livre le WFO, vectorbt a une API de splitter sophistiquée, NautilusTrader fait tourner une stack double Python+Rust, mais aucun d’eux ne réunit les quatre avec un contrat de parité publié.
L’autre axe à noter : chaque contrôle de réalisme, frais, slippage, funding, SL/TP intrabar, fenêtres de session, dimensionnement en pips forex, plafonds de levier partiel, est un paramètre du moteur, pas de la stratégie. Un auteur de stratégie ne peut pas oublier d’appliquer le slippage ou sauter les charges de funding ; le moteur les applique à chaque trade dans chaque fenêtre WFO dans chaque overlay de robustesse.
Comparaison de fonctionnalités · avril 2026
| Framework | Licence | WFO intégré | LB par régime | Tests LAH stricts | Parité inter-langages |
|---|---|---|---|---|---|
| ce travail (Py + Rs) | Apache-2.0 | ✓ | ✓ | ✓ | ✓ |
| vectorbt | Apache + CC | ✓ (Splitter) | - | - | n/d |
| backtrader | GPL-3.0 | - (communauté) | - | - | n/d |
| NautilusTrader | LGPL-3.0 | - (moteur seul) | - | - | - (bilingue ; pas de parité) |
| zipline-reloaded | Apache-2.0 | - (tiers) | - | - | n/d |
| QuantConnect Lean | Apache-2.0 | ✓ | - | - | n/d |
| bt | MIT | - | - | - | n/d |
Tests LAH stricts = no-look-ahead strict imposé par des tests de propriété automatisés au niveau du registre de trades.
Vérifié contre la documentation primaire, avril 2026. La combinaison WFO + LB par régime + LAH strict + parité inter-langages est, à notre connaissance, unique à ce travail.
Vitesse empirique
Même charge de travail, six moteurs, un protocole de chronométrage
100 stratégies échantillonnées depuis le générateur combinatoire du framework, chacune prise de bout en bout à travers un balayage de lookback in-sample, une optimisation RRR, et une évaluation out-of-sample. Mêmes barres SOLUSDT 1 heure, mêmes coûts (frais + slippage là où le moteur les supporte), même budget mono-thread, génération de signal et moteur de backtest tous deux dans la région chronométrée.
Temps mur mono-thread, 100 stratégies, SOLUSDT 1h
| Moteur | Temps mur | vs port Rust |
|---|---|---|
| ce travail (port Rust) | 6,3 s | 1×, le plus rapide |
| ce travail (Python) | 37,5 s | 6× plus lent |
| vectorbt | 4,1 min | 39× plus lent |
| backtesting.py | 23,7 min | 226× plus lent |
| backtrader | 13,4 h | 7 670× plus lent |
| bt | 37,2 h | 21 340× plus lent |
Mono-thread, de bout en bout (génération de signal + moteur de backtest). Stratégies identiques, découpe IS/OOS identique, hypothèses de frais + slippage identiques ; le funding n’est facturé que là où le moteur le supporte d’origine.
Backtrader et bt ont été parallélisés sur 15 workers pour tenir en temps d’horloge ; le total équivalent mono-thread est rapporté ici pour une comparaison à périmètre égal. bt est un framework de rééquilibrage de portefeuille plutôt qu’un simulateur de trades directionnels et n’est inclus que pour borner l’extrémité la plus lente de la comparaison.
Modèle de confiance
Pourquoi on peut faire confiance aux chiffres
La reproductibilité est une revendication à quatre couches : l’algorithme a des tests qui attrapent les modes de défaillance qui comptent, deux implémentations indépendantes s’accordent sur la sortie, la méthodologie cite et applique la littérature statistique publiée, et chaque artefact est ouvertement licencié et archivé avec un DOI pour qu’un tiers puisse tout reconstruire et re-vérifier.
01 · Invariants testés par propriété
Des tests de propriété basés sur Hypothesis vérifient l’invariant no-look-ahead au niveau du registre de trades : l’indice d’entrée de chaque trade doit être strictement supérieur à l’indice auquel le paramètre a été ajusté. Un test d’invariant d’ajustement-de-détecteur séparé fixe le détecteur de régime par défaut comme causal sous des perturbations de queue de barre, et signale explicitement les détecteurs KMeans / vol-quantile / trend-vol comme anti-patterns documentés plutôt que de laisser leur fuite passer en silence.
02 · Parité inter-langages
210 points de métrique vérifiés à travers trois surfaces de configuration (défaut · régime + WFO · forex) à une tolérance relative de 10⁻³. La pire déviation observée sur les 210 points est 5×10⁻⁵, vingt fois plus serrée que la bande déclarée. Le harnais de parité tourne à chaque PR ; une revendication méthodologique qui survit à cette barre doit soit correspondre à un bug équivalent dans les deux moteurs, soit être attrapée.
03 · Citations de la littérature publiée
Le préprint d’accompagnement (44 pages, 12 tours de relecture interne, score moyen 7,0 → final 8/8/9) cite 42 références à travers le Deflated Sharpe Ratio (Bailey & López de Prado), la CV combinatoire-symétrique / PBO (Bailey-Borwein-LdP-Zhu), la littérature des tests multiples (Harvey-Liu, Bonferroni / Holm / BHY), la famille du bootstrap-data-snooping (Reality Check de White, Romano-Wolf step-down), et les fondations du changement de régime (Hamilton, Ang-Timmermann). Les diagnostics livrés avec le moteur implémentent ces méthodes, pas des approximations de celles-ci.
04 · Ouvert, doté d’un DOI, et re-vérifiable
Les deux artefacts sont sous licence Apache-2.0 et archivés avec un DOI sur Zenodo (10.5281/zenodo.19798594 pour Python · 10.5281/zenodo.19798592 pour Rust). Le dépôt de l’article livre requirements-paper.txt avec des dépendances Python épinglées et une cible Makefile make verify qui ré-exécute les harnais de parité contre des SHA de clones jumeaux épinglés et régénère le CSV des résidus par métrique. Reproduire chaque figure et chaque revendication de parité de ce travail prend 5–10 minutes sur un ordinateur portable récent.
À l’intérieur de l’optimiseur
Ce qui rend l’optimiseur plus efficace qu’un balayage de grille
La plupart des backtesters exposent une grille de paramètres et laissent l’utilisateur exécuter un balayage exhaustif. Ce framework ajoute trois choses par-dessus : une recherche grossière-puis-fine qui divise par deux le coût de recherche sans perdre l’optimum, un garde d’optimisation intelligente qui rejette les pics aigus de PF avant qu’ils ne sur-ajustent la fenêtre in-sample, et une sonde RRR qui choisit le ratio risque-récompense maximisant le R total réalisé par fenêtre WFO.
La passe grossière balaie la plage de lookback {12, 14, ..., 76} sur une grille au pas de 2 (33 candidats), évalue la stratégie sur chacun, et classe par la métrique d’optimiseur configurée (Sharpe par défaut ; Profit Factor, Expectancy, MaxDD aussi configurables). Le meilleur candidat grossier déclenche alors une passe d’ajustement fin sur son voisinage ±1, trois évaluations supplémentaires. Nous n’avons pas vu l’étape d’ajustement fin diverger de l’optimum exhaustif sur aucun jeu de données testé.
Le garde d’optimisation intelligente se place devant le résultat grossier-puis-fin. Un candidat dont le Profit Factor dépasse le PF médian de ses voisins immédiats de plus de 10 % est rejeté comme pic aigu et le second est promu. Le seuil de 10 % est honnêtement divulgué comme de l’ingénierie empirique, c’est la valeur à laquelle une réduction qualitative du sur-ajustement OOS a été observée sur un panel de stratégies synthétiques, et le comportement on/off du garde fait partie de la surface de parité pour que quiconque puisse le basculer et voir l’effet.
La sonde RRR est le troisième étage. Pour chaque candidat RRR ∈ {1, 2, 3} (classique) ou {1, 2, 3, 4, 5} (chemin-régime), le moteur recalcule le R réalisé par trade comme min(peak_R, RRR) pour les trades qui touchent le SL en premier (profit plafonné) et le close-R réel pour les trades qui sont sortis avant de toucher le TP candidat. Le RRR★ choisi est celui qui maximise ΣR. C’est ce qui permet à un auteur de stratégie de brancher une seule règle et de laisser le moteur trouver un ajustement risque-récompense sensé plutôt que de deviner.
- Les trois étages tournent à l’intérieur de chaque sous-fenêtre WFO, jamais sur l’échantillon complet, donc l’invariant no-look-ahead est préservé au niveau du registre.
- La sélection de lookback par régime exécute les trois mêmes étages restreints aux barres dont l’étiquette est r, produisant un vecteur {lb★_r} de longueur égale au nombre d’étiquettes de régime. En OOS le moteur fait tourner l’étendue de la slow-EMA barre par barre.
- Tous les boutons de l’optimiseur sont des champs Config. Il n’y a aucun défaut caché à l’intérieur des kernels numba ou des closures Rust, basculer l’un d’eux est un changement d’une ligne reproductible contre le registre de parité.
Rotation de paramètres par régime
La plupart des backtesters exposent un paramètre et laissent l’utilisateur le choisir. Quelques-uns exposent une grille de paramètres et laissent l’utilisateur exécuter un balayage. Presque aucun ne livre un optimiseur intégré, et ceux qui le font n’optimisent pas par régime. Ce framework fait les deux : il balaie la plage de lookback à l’intérieur de la fenêtre in-sample, restreinte aux barres dont l’étiquette de régime est r, et produit un lb★_r séparé par régime. En OOS le moteur fait alors tourner l’étendue de la slow-EMA barre par barre selon l’étiquette de régime en direct, de sorte que la stratégie tourne avec le lookback qui a le mieux performé sur les barres qui ressemblent réellement au régime courant.
Toute la machinerie, balayage grossier-puis-fin, garde d’optimisation intelligente, sonde RRR, restriction par régime, rotation OOS, tourne sans aucune intervention de l’utilisateur. Un auteur de stratégie écrit la fonction (df, lb) → int8[] et configure le détecteur de régime (par défaut EMA-200 à 8 barres ; branchable pour vol-quantile, KMeans, ou une fonction personnalisée). Tout le reste est le travail du moteur. Il y a une sécurité régime-vide : si un régime a moins de min_trades à l’intérieur de la fenêtre IS, son lb★_r se rabat sur l’optimum IS global pour que la rotation ne produise jamais en silence un comportement à zéro trade.
Feuille de route par phases
5 faits · 1 en cours · 3 planifiés · cliquez sur n’importe quel nœud pour les détails
- Done
quant-research-framework v0.6.0, backtester Apache-2.0 installable par pip avec WFO, segmentation de régime, et une suite de robustesse à 5 scénarios prête à l’emploi.
- Done
quant-research-framework-rs v0.6.0, moteur Rust piloté par la spécification avec une sémantique de stratégie identique, prêt pour un déploiement en production.
- Done
Deux moteurs, une spécification : 210 points de métrique à travers 3 surfaces (défaut · régime+WFO · forex) vérifiés à une tolérance relative de 10⁻³.
- Done
Le port Rust est assez rapide pour la production : 33–65× moins de mémoire de processus complète et une accélération de 23.8–57× de bout en bout sur le bench fourni.
- Done
Préprint LaTeX de 44 pages, 12 tours de relecture interne (moy 7,0 → final 8/8/9). Soumission arXiv en attente.
- Done
Cross-compilation ARM64 sous QEMU : chaque métrique déterministe est byte-identique à x86_64 sur les six jeux de données. Les jobs ARM natif et QEMU sont tous deux intégrés à la CI.
- Done
Paires, paniers, portefeuilles couverts en bêta sur un registre par-jambe repensé. Livré en v0.5.0 ; huit surfaces de parité concordent à 1e-3 près, sortie mono-actif byte-inchangée.
- Done
Régime + WFO + forex + session. Close : un décalage de réglage dans le harnais plus trois divergences de barre de fin de session dans le cœur Rust, désormais alignées. Le combo est byte-exact et contrôlé en CI (v0.5.0).
- Done
Le Deflated Sharpe Ratio est désormais mis en miroir en Rust et vérifié en parité inter-langage (à 1e-3 près, et en deçà de 1e-9 sur les cas finis), amenant le bloc de diagnostics à la parité de fonctionnalités avec le moteur.
Cliquez sur un nœud vert pour ce qui est livré ; un nœud en accent pour ce qui est en cours ; un nœud en contour pour ce qui est planifié
Phase 01 · Fait · v0.6.0 · Apache-2.0
Moteur de référence Python
La référence Python est le framework que n’importe qui peut installer dès aujourd’hui et utiliser pour générer des stratégies, à base de règles ou de ML, sous un pipeline de qualité recherche. Vous écrivez une fonction qui prend (df, lb) et renvoie des signaux int8 dans {−1, 0, +1} ; le framework s’occupe de l’optimisation, de l’orchestration walk-forward, de la rotation de régime, de la suite d’overlays de robustesse à 5 scénarios, et du calcul des métriques. La boucle interne JIT numba applique frais, slippage, funding (crypto-seulement), SL/TP intrabar, fenêtres de session, et logique de clôture forcée sur un registre de trades typé, de sorte que le PnL simulé est ce qu’une couche d’exécution déployable verrait réellement.
Sept sous-systèmes majeurs sont livrés d’emblée, chargeur de données, cœur d’indicateurs, contrat de stratégie, cœur d’exécution, optimiseur, orchestrateur walk-forward, moteur de régime, plus les blocs de diagnostics Monte Carlo et Deflated-Sharpe. La version v0.4.0 a démêlé Config des globales, ce qui permet à deux backtests de coexister dans le même interpréteur et a aussi débloqué le protocole de parité inter-langages en aval.
- Installer : pip install quant-research-framework. DOI : 10.5281/zenodo.19798594. Sous licence Apache-2.0.
- Le contrat de stratégie est délibérément minimal : (df, lb) → int8[] dans {−1, 0, +1}. Même surface pour les règles écrites à la main et pour les modèles de ML.
- CSV fournis pour faire du premier backtest une seule ligne : SOLUSDT 1h (48 094 barres) et EURUSD 1h (53 160 barres).
Phase 02 · Fait · v0.6.0 · Apache-2.0
Port Rust, ré-implémentation pilotée par la spécification
Le port Rust vous donne le même moteur, même WFO, même segmenteur de régime, même suite de robustesse, même sémantique de stratégie, dans un binaire que vous pouvez déposer dans un déploiement de production sans interpréteur Python. C’est une implémentation séparée de la même spécification, pas une translittération : disposition mémoire différente, régime d’arrondi différent (LLVM-via-rustc vs LLVM-via-numba), RNG différent. Le but est d’exercer la spécification algorithmique avec deux moteurs dont la seule lignée partagée est la spécification elle-même.
Le contrat de stratégie reflète Python exactement : fn(&[Bar], usize) → Vec<i8>. La couche de détection de bascule traduit les niveaux de signal bruts en codes d’entrée/sortie ; cette séparation permet aux auteurs de stratégie de spécifier l’état désiré (long/short/flat) plutôt que les transitions, ce qui est bien plus facile à garder correct vis-à-vis du no-look-ahead.
- DOI : 10.5281/zenodo.19798592. crates.io : cargo add quant-research-framework-rs.
- Les dépendances sont délibérément minuscules et épinglées : rand =0.9 (exact), chrono 0.4, chrono-tz 0.10. L’épinglage exact de rand est documenté parce que rand 0.10 fait de random_range une méthode de trait, cassant les sites d’appel.
- Le binaire Rust n’a besoin d’aucune mise en chauffe ; Python paie un coût unique de cache JIT numba avant la première exécution mesurée.
Phase 03 · Fait · preuve que les deux moteurs sont le même moteur
Protocole de parité inter-langages
La parité est le protocole qui nous permet d’affirmer que Python et Rust exécutent le même backtester plutôt que deux backtesters qui se ressemblent par hasard. Trois surfaces de configuration déterministes sont vérifiées de bout en bout à chaque PR : config par défaut (56 points de métrique · WFO déclenché par bougie + lookback smart-optimisé + auto-RRR), régime + WFO (98 points de métrique · optimisation de LB par régime + rotation de LB OOS + warmup de 200 barres + 4 fenêtres WFO), et mode forex (56 points de métrique · dimensionnement de position à l’échelle des pips + plafonnement de PnL en mode forex).
La tolérance est de 10⁻³ relatif ; la pire déviation observée sur les 210 points de métrique est 5×10⁻⁵, vingt fois plus serrée que déclarée, ce que nous prenons comme preuve que c’est l’équivalence algorithmique, pas l’accumulation numérique, qui est contraignante. La réplication à 210 points au moment de l’article a correspondu bit à bit à la précision d’arrondi d’impression \%.4f.
- Ré-exécuter la parité est une commande par surface, durée totale ≈ 5–10 min sur un ordinateur portable récent.
- Désactivés par conception : les percentiles Monte Carlo (implémentations de RNG différentes entre moteurs) et l’overlay INDICATOR_VARIANCE — un décalage de lookback de ±1 dont la graine n’est pas fixée, aléatoire par intention, de sorte que ces lignes varient d’une exécution à l’autre dans chaque moteur et restent hors de la surface de parité.
- Périmètre non vérifié honnêtement divulgué : Windows MSVC. La combinaison à quatre voies régime+WFO+forex+session est désormais byte-exacte et contrôlée en CI (Phase 08), et la parité inter-architectures sur aarch64 est vérifiée par CI (Phase 06).
Phase 04 · Fait · harnais de bench publié
Performance, le port Rust est assez rapide pour la production
L’intérêt de la phase de perf est que le moteur Rust est opérationnellement utilisable dans un déploiement de production, pas que la référence Python soit lente. Sur le bench fourni le port Rust tourne 23.8–57× plus vite de bout en bout avec 33–65× moins de RSS de pic de processus complet, le delta de mémoire attribuable au moteur n’est plausiblement que de 3–5× une fois soustraite la baseline de l’interpréteur pandas/numpy/numba de Python, et l’article lit la une avec cette réserve.
La comparaison d’accélération est significative précisément parce que la parité tient : sans parité, une ré-implémentation plus rapide pourrait simplement faire moins de travail ; avec parité, vous chronométrez deux implémentations du même algorithme.
- Les benchmarks tournent sur des tranches SOLUSDT 1h fournies à 15k / 25k / 35k / 48k barres, trois exécutions à chaud (avec une mise en chauffe écartée pour le cache JIT numba).
- Le pipeline par défaut complet tourne de bout en bout : baseline IS/OOS, recherche de lookback smart-optimisée avec auto-RRR, walk-forward déclenché par bougie, diagnostics Monte Carlo, et les quatre overlays de robustesse v0.1.x.
Phase 05 · Fait · 44 pages · ~715 Ko PDF
Préprint du backtester walk-forward reproductible
L’article d’accompagnement documente l’architecture, le pipeline WFO + régime + robustesse, la méthodologie de parité, la comparaison de performance, et un plan de reproductibilité adapté à une publication académique. Il positionne le framework contre six backtesters open-source largement utilisés et la littérature statistique pertinente ; la contribution est la combinaison plus le protocole de parité, pas une nouvelle machinerie statistique.
Douze tours de relecture interne ont fait passer l’article d’un score moyen de relecteur de 7,0 à une trajectoire finale de 8/8/9. Le dépôt de l’article livre requirements-paper.txt avec des dépendances Python épinglées, un Makefile qui exécute make verify contre des SHA de clones jumeaux épinglés, et un parity_residuals.csv généré qui sous-tend chaque figure.
- Source complète : github.com/DaruFinance, dépôt de l’article + dépôt python + dépôt rust en jumeaux.
- Les deux artefacts ont des DOI Zenodo séparés ; le dépôt de l’article recevra son propre DOI lorsqu’il sera archivé sur Zenodo au moment de la publication.
Phase 06 · Terminée · byte-identique sur aarch64, CI QEMU + ARM natif au vert
Parité inter-architectures
Le port Rust a été cross-compilé vers aarch64-unknown-linux-gnu et exécuté sous l’émulation en mode utilisateur QEMU contre les mêmes entrées que le binaire x86_64. Après avoir semé l’overlay de variance-d’indicateur précédemment non semé (un oubli découvert et corrigé pendant la préparation de l’article), chaque métrique déterministe imprimée est byte-identique entre les deux architectures sur les six jeux de données, 1 176 lignes de métrique, zéro différence. Seuls les temps de chargement et de temps mur total diffèrent, tous deux gonflés par le surcoût d’émulation de QEMU.
La comparaison est une égalité de chaîne exacte du bloc de métriques imprimé, strictement plus forte que la vérification par tolérance relative utilisée pour la parité inter-langage, et elle tient parce que le hot path n’utilise que des opérations IEEE-754 correctement arrondies, sans fast-math ni codegen de fused-multiply-add. Un job ARM natif sur un runner ARM public gratuit exécute la même assertion de byte-identité sur silicium réel aux côtés du job QEMU, de sorte que les deux architectures sont vérifiées à chaque changement et que le résultat QEMU sert de filet de sécurité reproductible.
Phase 07 · Terminée · publiée en v0.5.0 dans les deux moteurs
Cœur multi-actifs
Le cœur d’exécution, à la version épinglée par l’article, opérait sur une seule série OHLC à la fois. Le substrat multi-actifs qui lève cette limite a été livré en v0.5.0 dans les deux moteurs : une couche panel (détection de régime inter-actifs, paniers long/short, dimensionnement par equal-risk-contribution, neutralisations bêta / dollar / sigma, contraintes de portefeuille) plus des primitives de paires et de carry, sur un registre de trades par-jambe repensé qui porte un id de jambe, un id de groupe de trade et une décomposition complète des coûts (frais, slippage, funding, brut et net) satisfaisant brut − coûts = net à la tolérance flottante.
Chaque primitive est mise en miroir Python ↔ Rust et contrôlée par sa propre porte de parité en CI, avec la même discipline que les surfaces d’origine, huit surfaces concordent désormais à 1e-3 près (nombre de trades exact). La sortie mono-actif est byte-inchangée par rapport à la version précédente. La recherche de stratégies propriétaire qui repose sur ce substrat reste privée ; la publication publique est la capacité du moteur, pas les stratégies.
Phase 08 · Terminée · byte-exacte et contrôlée en CI (livrée en v0.5.0)
Surface de parité à quatre voies (régime + WFO + forex + session)
Le registre de parité publié couvrait trois surfaces ; la combinaison à quatre voies, régime + WFO + forex + session, était celle qui restait, et elle est désormais close. L’investigation a révélé deux causes. La dominante était un décalage dans le harnais, et non un bug du moteur : le pilote du combo alimentait les deux moteurs avec des réglages de sélection différents (le minimum de trades et l’optimisation du risk-to-reward sont des constantes de compilation côté Rust mais étaient surchargés côté Python), si bien que la phase in-sample choisissait un lookback différent.
Le résidu était trois divergences de barre de fin de session dans le cœur Rust : sur la dernière barre en-session du jour, il laissait un signal de flip opposé ouvrir une position, ne bloquait jamais une nouvelle entrée, et exécutait la vérification intrabar de stop/cible, alors que le moteur de référence force la clôture inconditionnellement et saute la vérification stop/cible. Aligner les trois (entièrement protégé par le drapeau de session, donc les surfaces à fonctionnalité unique restent byte-inchangées) rend le combo byte-exact à chaque étage. Il s’exécute désormais comme une quatrième surface de parité contrôlée en CI, rétrécissant l’empreinte non-vérifiée honnêtement divulguée à Windows MSVC.
Phase 09 · Terminée · miroir Rust livré et vérifié en parité
Deflated Sharpe Ratio en Rust
L’utilitaire DSR (Bailey & López de Prado 2014) était Python-seulement parce qu’il dépend de la distribution normale de scipy et est invoqué une fois par trajectoire d’optimisation plutôt que par barre. Il est désormais mis en miroir en Rust derrière un drapeau de fonctionnalité léger, avec la même discipline de parité appliquée à sa sortie scalaire : un harnais dédié alimente des fixtures identiques de (Sharpe, Sharpes d’essai, rendements), y compris les cas asymétriques, à queue épaisse et tous les cas-garde dégénérés, aux deux implémentations et confirme la concordance sur le Sharpe-maximum-attendu et le Sharpe déflaté dans la tolérance standard, et en fait en deçà de 1e-9 sur tous les cas finis puisque les deux sont en forme close.
La CDF normale et son inverse proviennent d’un crate de statistiques éprouvé qui concorde avec scipy à environ 1e-12 ; l’approximation grossière de la fonction d’erreur utilisée ailleurs dans le port n’est délibérément pas réutilisée, car son erreur de queue corromprait le terme de Sharpe-maximum-attendu au quantile pertinent. Le bénéfice est un déploiement Rust-seulement qui calcule des diagnostics de Sharpe déflaté sur ses propres trajectoires d’optimiseur sans aller-retour par Python.
Reproductibilité
quant-research-framework
Python · Apache-2.0 · DOI 10.5281/zenodo.19798594
quant-research-framework-rs
Rust · Apache-2.0 · DOI 10.5281/zenodo.19798592
Reproduire la parité en 5–10 minutes
git clone …/quant-research-framework
git clone …/quant-research-framework-rs
cd quant-research-framework-rs
cargo build --release
QRF_PY_DIR=../quant-research-framework \
python tools/parity_check.py --tol 0.001
QRF_PY_DIR=../quant-research-framework \
python tools/parity_regime.py --tol 0.001
QRF_PY_DIR=../quant-research-framework \
python tools/parity_forex.py --tol 0.001
