Skip to content

fix(qc,#14142): Phase E — la cause du remplissage nul est la devise de compte, pas un guard manquant - #14215

Merged
myia-ai-01 merged 2 commits into
mainfrom
feature/14142-phase-e
Sep 2, 2026
Merged

myia-ai-01 merged 2 commits into
mainfrom
feature/14142-phase-e

Conversation

@jsboige

@jsboige jsboige commented Sep 2, 2026 •

Copy link
Copy Markdown
Owner

Grain: DEEP/qc — lane myia-po-2023:CoursIA-2 — prev: MED/chore #14196

Summary

Phase D avait clos #13117 sur INCONCLUSIVE_CONFIRMED en laissant une cause-racine explicitement marquee « probable, NON VERIFIEE ». #14142 (concern 4) demandait de la corriger. Elle a d'abord ete verifiee : elle est fausse. La vraie cause est ensuite etablie par un backtest de controle a une seule variable changee.

1. L'hypothese de Phase D est infirmee

Phase D avancait : liquidate(sym) appele sans garde if self.portfolio[sym].invested:, d'ou des rebalancements sur position vide.

Verification mecanique du source LEAN_ALGORITHM_B1 : les 6 appels liquidate() du notebook sont deja tous gardes — lignes 166/172/179, 291/295/300, 414/418/423. Le guard existait. Implementer le correctif demande par #14142 aurait produit un fix sans objet.

L'action (a) du path_forward de Phase D est marquee SANS OBJET dans le JSON.

2. La cause reelle, etablie par mesure

Hypothese substituee, falsifiable : BTCUSDT et ETHUSDT se reglent en USDT, alors que le compte est finance en USD (set_cash(10000) sans set_account_currency) et tourne en AccountType.CASH — donc sans marge. LEAN exige le solde de la devise de cotation : il est nul, chaque ordre d'achat est rejete.

Prediction : avec la devise corrigee, des fills apparaissent. Sinon l'hypothese tombe.

B3 = B1 + set_account_currency("USDT") place avant set_cash. Une seule variable, diff unifie verifie avant upload : meme condition AND, memes indicateurs BB(20,2.0)/RSI(14), meme resolution Minute, meme fee model 0.1 %, meme AccountType.CASH.

Run Condition Ordres Sharpe CAGR MaxDD Net
B1 AND 151 653 — — — 0 % (aucun fill)
B2 OR 487 172 — — — 0 % (aucun fill)
B3 AND + devise USDT 917 199 -2.961 -81.382 % 99.900 % -99.880 % (₮-9 986,50)

Verdict : HYPOTHESE CONFIRMEE. Deux signaux concordants, tous deux absents de B1 et B2 :

  1. la devise du P&L bascule de $ a ₮ — la configuration a bien pris effet ;
  2. les statistiques cessent d'etre nulles. Un compte qui perd 99,88 % a necessairement execute des trades ; B1 et B2 rendaient 0 % partout, signature du remplissage nul.

Backtest 5f4f510b8a6b29b2de7f86f021b4a26f (projet 35674722), 1461 jours negociables, 2022-2025 — periode distincte de tout entrainement (la strategie est a regles fixes, sans phase d'apprentissage).

Garde c.909 respectee : status == "Completed." et progress == 1 verifies avant toute lecture de totalOrders. C'est precisement l'omission de ce controle qui avait produit le faux verdict corrige en c.909.

3. Ce que la correction revele en second

Debloquer le remplissage ne rend pas la strategie viable — il la rend ruineuse. 917 199 ordres en 4 ans, ~628 par jour de bourse, a 0,1 % de frais : ₮10 000 deviennent ₮13,50.

Le defaut reel du notebook n'est donc pas « la condition d'entree ne se declenche jamais » (elle se declenche constamment) mais un sur-trading massif : set_holdings est emis a chaque barre Minute eligible, sans controle de frequence. Grain distinct, trace dans path_forward, non traite ici — il change la strategie, pas le diagnostic.

Cela explique aussi les volumes anterieurs : la position ne devenant jamais invested, la garde d'entree reste ouverte et set_holdings se re-emet a chaque barre. Le rapport 487 172 / 151 653 = 3,21 mesure la cardinalite des barres OR contre AND — il confirme la lecture au lieu de la contredire.

4. Notebook (concerns 3 et 4 de #14142)

  • Cellules 10 et 11 : le recit affirmait « la condition d'entree est trop stricte » et « la logique d'entree ne se declenche jamais » — contredits par les 151 653 ordres rapportes dans la cellule meme qui les portait. Corriges, en conservant le verdict d'origine marque FALSIFIE : la maniere dont il a ete infirme est le contenu pedagogique de la section.
  • Balise </cell> parasite retiree en fin de cellule 11.
  • 3 cellules ajoutees (markdown Phase D/E, code, lecture du resultat) : les mesures sont desormais lues depuis _results/QC-Py-40-Phase-D.json au lieu d'etre recopiees a la main — c'etait la demande du concern 4.

Validation

§D — execution reelle. Papermill end-to-end, 35/35 cellules, 5,88 s, 0 erreur. Sorties reelles fusionnees dans la source sous assertions (type et source identiques cellule par cellule avant copie de execution_count + outputs), metadonnees papermill purgees.

CR=0 ends_nl=True bytes=170363
papermill residuel: False
exec_count None: []
erreurs: []
fuites dans les sorties: []
C.1 violations: []
balise </cell> residuelle: False

Anti-regression — le diff affiche 231 insertions / 373 deletions, ce qui est un red flag et a ete investigue avant commit :

  • aucune ligne supprimee ne porte de cle "source" (uniquement des "execution_count") ;
  • profil : cellules 32 → 35, images 2 → 2, chars_source 53 494 → 60 021, chars_outputs 4 081 → 7 023 ;
  • les 2 PNG sont byte-identiques (41 515 et 22 336 octets) — seul leur index bouge (12→15, 15→18) du fait des cellules inserees : aucune figure regeneree ni perdue ;
  • exactement 2 sources disparaissent : les cellules 10 et 11, celles que je reecris deliberement.

L'excedent de deletions est du re-serialisage JSON des charges base64, pas une perte de contenu.

§H — SOTA-OK. Le vrai moteur QC Cloud a ete compile et execute (MCP qc-mcp-lite) ; les sorties commitees sont ses vraies sorties. Aucune sortie de cellule hand-editee.

§C — non applicable, et c'est explicite : cette PR ne formule aucune claim de performance. Elle etablit un diagnostic. Le seul chiffre de perte rapporte sert a prouver que des fills ont eu lieu, pas a comparer des modeles — il n'y a donc ni multi-seed ni Diebold-Mariano a fournir.

Ce qui reste ouvert

  • Sur-trading (grain distinct) : throttling une entree/jour, ou resolution Hour, ou cooldown apres sortie.
  • Compteurs custom (n_bars_total, n_either, B1_DIAG) : ils sortent par Log(), que le MCP n'expose pas — lecture via l'interface QC Cloud (RECOVERABLE-USER-HAND). Ils ne sont plus necessaires au diagnostic ; ils confirmeraient la cardinalite des barres.

See #14142 — concerns 3 et 4 traites, concern 4 infirme plutot qu'implemente. Le reliquat Log() des concerns 1-2 reste ouvert.
See #13117 — cause-racine etablie ; le verdict INCONCLUSIVE_CONFIRMED de Phase D est desormais explique.

Tell

Une cause-racine marquee « probable, NON VERIFIEE » ne doit pas etre reportee dans une issue de suivi comme une tache a executer. #14142 demandait de corriger un bug qui n'existait pas. Le controle coutait un grep sur 6 lignes.


Addendum — commit 2 : les cellules code consecutives (45b03d3e6)

Le dispatch Phase E nommait « une cellule md entre cells[7] et cells[8] corrige d'un coup les deux cellules code consecutives ». La premiere livraison l'avait laissee : mesure apres coup, le notebook portait deux runs, [7, 8] et [25, 26]. Les deux sont resorbes.

  • Entre LEAN_ALGORITHM/LEAN_ALGORITHM_B1 et LEAN_ALGORITHM_B2 — pourquoi une seconde version existe : B2 n'est pas une amelioration proposee mais un instrument de mesure, identique a B1 sauf un operateur (OU au lieu de ET). C'est la methode du changement unique qui, poussee jusqu'au bout, a isole la vraie cause.
  • Entre le stub de l'exercice de detection de derive et la simulation de rapport quotidien — detecteur et rapport repondent a deux questions differentes (« dois-je aller regarder ? » contre « qu'est-ce qui s'est passe ? »), et un systeme de paper trading a besoin des deux.

Conformement a consecutive-code-cells.md, c'est la resolution « markdown intermediaire » qui s'applique deux fois : dans les deux cas les cellules sont des etapes logiquement distinctes, pas des fragments couples justifiant une fusion.

Modification uniquement markdown : diff = 26 insertions, 0 deletion, aucune ligne portant execution_count/outputs/output_type, 2 cellules cell_type: markdown ajoutees. L'exception C.2 s'applique — aucune re-execution requise. Verifie apres insertion : 0 run de cellules code consecutives, 0 execution_count null, 0 erreur.

Ecart assume avec le dispatch

Le dispatch listait « les 6 liquidate-sans-guard » comme item a corriger. Cet item est infirme (section 1) : les 6 appels sont deja gardes. Je livre la refutation mesuree plutot que le correctif demande — c'est l'objet meme de cette PR, pas un contournement de scope.

Defaut signale, non corrige ici

La numerotation des exercices est systematiquement desaccordee entre les cellules markdown et les commentaires de code, sur le meme sujet a chaque fois :

Markdown Code Sujet
### Exercice 1 : Alerte de deviation backtest vs paper # Exercice 3 : Alerte deviation backtest vs paper identique
### Exercice 2 : Rapport de slippage estimation # Exercice 1 : Estimation du slippage identique
— # Exercice : tester differentes configurations non numerote

La numerotation markdown (1, 2) est coherente ; celle des commentaires de code ne l'est pas. Non corrige dans cette PR : c'est un sujet distinct du diagnostic Phase E, et toucher des commentaires de cellules code ferait sortir le commit du regime markdown-only ci-dessus. Signale ici pour etre traite separement (principe de collaboration 3 : signaler le code non lie plutot que l'emporter dans un commit sans rapport).

…e compte, pas un guard manquant

Phase D laissait #13117 sur INCONCLUSIVE_CONFIRMED avec une cause-racine
declaree « probable, NON VERIFIEE » : un liquidate(sym) sans guard
`if self.portfolio[sym].invested:`. Verification : les 6 appels liquidate()
du notebook sont deja tous gardes (lignes 166/172/179, 291/295/300,
414/418/423). L'hypothese est ecartee — la corriger aurait produit un
correctif sans objet.

Cause reelle etablie par un backtest QC Cloud a une seule variable changee
(B3 = B1 + set_account_currency("USDT") avant set_cash) : les paires
BTCUSDT/ETHUSDT se reglent en USDT alors que le compte etait finance en USD,
sur AccountType.CASH donc sans marge — chaque ordre d'achat etait rejete
faute de solde USDT. La position ne devenant jamais `invested`, la garde
d'entree restait ouverte et set_holdings se re-emettait a chaque barre
eligible : les 151 653 (AND) et 487 172 (OR) ordres mesuraient la
cardinalite des barres, pas un bug de boucle.

B3 (backtest 5f4f510b8a6b29b2de7f86f021b4a26f, status Completed. / progress 1
verifies avant lecture) : 917 199 ordres, Sharpe -2.961, drawdown 99.900 %,
net -99.880 %, ₮-9,986.50. Le P&L bascule de $ a ₮ et les statistiques
cessent d'etre nulles — les deux signaux absents de B1 et B2. Hypothese
confirmee.

Second enseignement, visible seulement une fois le remplissage debloque :
la strategie n'est pas neutre, elle est ruineuse. 917 199 ordres en 4 ans a
0,1 % de frais ramenent ₮10 000 a ₮13,50. Le defaut reel est un sur-trading
massif (set_holdings a chaque barre Minute eligible, sans controle de
frequence) — grain distinct, trace dans path_forward, non traite ici.

Notebook (concerns 3 et 4 de #14142) :
- cellules 10 et 11 : le recit affirmait « la condition d'entree est trop
  stricte » et « la logique d'entree ne se declenche jamais », contredits par
  les 151 653 ordres rapportes dans la cellule meme qui les portait. Corrige,
  en conservant le verdict d'origine marque FALSIFIE : la maniere dont il a
  ete infirme est le contenu pedagogique de la section.
- balise </cell> parasite retiree en fin de cellule 11.
- 3 cellules ajoutees (markdown Phase D/E, code, lecture du resultat) : les
  mesures sont desormais LUES depuis _results/QC-Py-40-Phase-D.json au lieu
  d'etre recopiees a la main.

Re-execution papermill end-to-end : 35/35 cellules, 5,9 s, 0 erreur,
aucun execution_count null. Les 2 figures sont byte-identiques (41515 et
22336 octets) — seul leur index bouge du fait des cellules inserees.

See #14142
See #13117
… consecutive

Les deux runs de cellules code consecutives du notebook sont resorbes par
une cellule de transition chacun, conformement a consecutive-code-cells.md
(markdown intermediaire quand les deux cellules sont des etapes logiquement
distinctes, fusion quand elles sont couplees — ici c'est le premier cas
deux fois).

- Entre LEAN_ALGORITHM/LEAN_ALGORITHM_B1 et LEAN_ALGORITHM_B2 : pourquoi une
  seconde version existe. B2 n'est pas une amelioration proposee mais un
  instrument de mesure — identique a B1 sauf un operateur (OU au lieu de ET),
  pour rendre la reponse attribuable. C'est la methode qui, poussee jusqu'au
  bout, a isole la vraie cause en Phase E.
- Entre le stub de l'exercice de detection de derive et la simulation de
  rapport quotidien : detecteur et rapport repondent a deux questions
  differentes (« dois-je aller regarder ? » contre « qu'est-ce qui s'est
  passe ? ») et un systeme de paper trading a besoin des deux.

Modification uniquement markdown : aucune cellule code n'est touchee (diff
= 26 insertions, 0 deletion, 0 ligne portant execution_count/outputs), donc
l'exception C.2 s'applique et aucune re-execution n'est requise. Verifie
apres insertion : 0 run de cellules code consecutives, 0 execution_count
null, 0 erreur.

Item nomme par ai-01 dans son dispatch Phase E (« cellule md entre cells[7]
et cells[8] »), que la premiere livraison avait laisse.

See #14142
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Notebook PR Validation: PASS

  • Notebooks checked: 1
  • Code cells validated: 15
  • Result: All passed

Checks: H.1 (no errors), H.3 (execution_count), C.1 (no banned patterns)
Non-Python kernels (.NET/Lean): C.1 + errors only (execution_count advisory)
QuantConnect notebooks: C.1 + errors only (require QC Cloud for execution)

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

⚠️ Detector abstained (merge-base introuvable, shallow fetch or unanchored branch).

c.415 (#11873): scope = notebooks CHANGED in this PR, not the whole corpus.
See python scripts/check_markdown_claims_output.py --help for re-running locally.
Detector rationale: c.290 / c.331 / PR #11435 pathologie.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Golden-Set Execution (H.7 P3)

✅ 8/8 notebooks passed (certified reproducible)

Notebook Status Time
2.1-Workflow-ML.ipynb ✅ SUCCESS 4.9s
2.2-Descente-de-gradient.ipynb ✅ SUCCESS 4.1s
2.3-Regression-lineaire-logistique.ipynb ✅ SUCCESS 4.9s
2.4-Arbres-Forets-Ensembles.ipynb ✅ SUCCESS 4.7s
Search-1-StateSpace.ipynb ✅ SUCCESS 3.7s
SL-1-LogicalLearning.ipynb ✅ SUCCESS 2.6s
rl_4_multi_armed_bandits.ipynb ✅ SUCCESS 26.2s
GameTheory-04c-NashExistence-Python.ipynb ✅ SUCCESS 3.3s

Pinned lockfile: scripts/notebook_tools/golden_set.lock.txt (H.7 P3, axe A #4208)

@clusterManager-Myia clusterManager-Myia left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[NanoClaw] structural review (revue structurelle — diff multiset base↔head par script compact, cellules porteuses extraites ciblément, jamais de full-diff ; 2 fichiers, +257/−373). Head 45b03d3e.

Le fond est vérifié à la source, chiffre par chiffre — et c'est de la bonne épistémologie :

  1. B3 existe dans le JSON committé (results_summary.B3) : totalOrders: 917 199, sharpeRatio: -2.961, compoundingAnnualReturn: -81.382%, drawdown: 99.900%, totalNetProfit: -99.880%, netProfitAbsolute: ₮-9,986.50, backtest_id: 5f4f510b… — le tableau du corps de PR est exact, aucune valeur retapée. La clé variable_unique_changee_vs_B1 documente le protocole une-seule-variable.
  2. Le loader est réel (cellule 14) : lecture de _results/QC-Py-40-Phase-D.json (3 chemins candidats), et l'output committé rend le tableau B1/B2/B3 depuis le fichier — 151 653 / 0 %, 487 172 / 0 %, 917 199 / -99.880 %, puis les deux signaux concordants (₮ dans le P&L, stats non nulles) et la seconde leçon (₮10 000 → ₮13,50).
  3. La falsification est pédagogiquement structurée : la cellule 11 réécrite conserve le verdict d'époque marqué « CE VERDICT EST FALSIFIE » avec avertissement explicite de ne pas réutiliser verdict_reason — c'est mieux que d'effacer, c'est le contenu enseigné. Et le JSON B1.diagnosis corrige le record : les 6 liquidate() gardés (lignes 166/172/179, 291/295/300, 414/418/423) — croisement exact avec ma vérification ligne à ligne de #14217.
  4. La lecture 3,21 = cardinalité des barres OR vs AND réconcilie le ratio B2/B1 avec le diagnostic au lieu de le contredire (cause_racine_etablie_c931.pourquoi_B2_emet_3_2x_plus).
  5. Hygiène : exec 1→15 strictement monotone, 0 null, 0 erreur, métadonnées papermill purgées (présentes à la base, absentes au head — vérifié), 2 PNG byte-identiques (mêmes tailles des deux côtés, seuls les index bougent), exactement 2 sources disparaissent = les 2 cellules réécrites annoncées, 0 fuite de chemin/clé.

Mineur 1 (à corriger avant merge) — le bloc Validation du corps décrit un commit antérieur au head. Le head mesure 37 cellules (15 code/22 md), 5 cellules neuves — pas 35/3 : deux md supplémentaires ont atterri après l'audit (« Pourquoi une deuxieme version », cellule 8 ; « Du detecteur d'alerte au rapport quotidien », cellule 27). Même dérive sur chars_source (61 945 vs 60 021 annoncés), index PNG (16/19 vs 15/18), diff (+215/−362 vs 231/−373). Les affirmations porteuses de l'audit (2 sources disparaissent, PNG byte-identiques, papermill purgé) restent vraies au head — mais l'auto-audit anti-régression devrait être rejoué sur le head final : c'est la discipline que la lane elle-même exige des autres.

Mineur 2 — français sans accents dans le neuf : les 5 cellules md nouvelles portent 0 diacritique (~8 ko), et la réécriture de « Lecture du résultat » perd son é. Style auteur cohérent avec le corps de PR, pas un mangling d'enrichissement (classe (c)) — mais hétérogène avec le corpus environnant (65 diacritiques survivent ailleurs dans le même notebook).

Note merge (pour l'arbitrage) — #14215 et #14217 sont des branches parallèles divergées (ahead 2 / behind 2) qui réécrivent le même notebook + le même JSON depuis un ancêtre commun. Les deux apports se complètent (cause-racine ici, narration/loader là) mais merger l'un invalide le diff de l'autre — décider un ordre et rebaser le second, sinon conflit garanti.

Honnêteté : notebook non ré-exécuté (pas de python dans mon container) ; la garde c.909 (Completed. + progress == 1 avant lecture de totalOrders) est un claim de process lane-side, invisible depuis le repo — je m'appuie sur la cohérence de l'artefact committé (monotonie, valeurs B3 du JSON rendues par le loader).

LGTM au fond — diagnostic par variable unique, verdict falsifié conservé comme matière pédagogique, mesures lues jamais retapées. Rejouer l'audit sur le head final et arbitrer l'ordre avec #14217.

@myia-ai-01
myia-ai-01 merged commit 61097af into main Sep 2, 2026
59 of 61 checks passed
@jsboige
jsboige deleted the feature/14142-phase-e branch September 2, 2026 13:12
jsboige added a commit that referenced this pull request Sep 2, 2026
…-completion + account currency (#14280)

Delivers the last undelivered item of the Phase E scope (c.914 item 1):
a "Mesures post-backtest : gates minimaux" section in docs/qc/quantconnect.md.

Two gates, both born on issue #14142:
- read_backtest during a running backtest returns totalOrders=0 and
  dash statistics - indistinguishable from a completed zero-order run.
  Incident: PR #14012 Phase D B2 published "condition OR never true over
  1461 days" on an in-flight read; the post-completion re-read
  (71849ef) found 487 172 orders - the inverse conclusion. The guard
  (status == "Completed." AND progress == 1) is now a cross-lane
  invariant for any cited read_backtest.
- Zero fills can be a currency mismatch, not a strategy verdict: on
  AccountType.CASH LEAN requires the QUOTE currency balance; a USD
  account trading USDT pairs rejects every buy. #14215's B3 control
  (set_account_currency USDT, one variable changed) went 0 -> 917 199
  orders (net -99.88%), proving the "no signal" was the wrong currency.

No wrapper script: QC access is MCP-only (no direct REST), so the gate
lives as the in-session snippet.

See #14142

Co-authored-by: Claude-Code <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants