Skip to content

feat(pullback): banc portefeuille et verdict de la porte : FAIL (phase 3, F-46) - #112

Open
laurentvv wants to merge 1 commit into
feat/pullback-universe-datafrom
feat/pullback-bench
Open

laurentvv wants to merge 1 commit into
feat/pullback-universe-datafrom
feat/pullback-bench

Conversation

@laurentvv

Copy link
Copy Markdown
Owner

Résumé

Phase 3 du plan, empilée sur #111 (elle-même sur #110). Le banc est construit et son verdict, calculé par le code, est FAIL : la porte du plan (§2.1) n'est pas franchie, donc rien n'est construit côté exécution T212.

Résultat (test hors échantillon 2021-01-04 → 2026-10-12, net de frais 25 pb/sens et d'impôt 30 %)

CAGR Sharpe Drawdown max Espérance
Pullback (variante retenue au calibrage 2015-2020) −22,6 % −1,93 −78,9 % −0,55 R (680 trades)
Entrées au hasard (médiane de 40) −15,0 % −1,25 −64,6 % −0,45 R
B&H Nasdaq-100 EUR +14,6 % 0,74 −31,3 %
MA200 Nasdaq-100 EUR +9,7 % 0,65 −31,1 %
  • Les 6 variantes pré-enregistrées perdent toutes, au calibrage comme au test.
  • La stratégie est battue par 95-98 % des tirages au hasard : consolidation, support et AVWAP n'ajoutent rien dans cette traduction journalière.
  • Pas un artefact des hypothèses : avec l'ordre intrajournalier le plus favorable, elle reste négative (−7,8 %/an, −0,16 R). Le biais du survivant joue en sa faveur.
  • Limite : l'intraday de la source (bougies 1 à 15 min) n'est pas testé. La méthode d'origine est donc non testée, pas réfutée.

Contenu

  • src/pullback/market.py : pré-filtre vectorisé, identique à rules.detect_consolidation (0 écart sur 12 089 contrôles réels) et au screener.
  • src/pullback/portfolio.py : moteur événementiel OHLC (gaps payés, pire cas intrajournalier, change, frais, impôt).
  • src/pullback/bench.py : variantes, walk-forward, contrôles, bootstrap, Sharpe déflaté, verdict, rapport.
  • docs/BACKTEST_PULLBACK_2026-10-12.md (généré) + §9 du plan.
  • 15 tests moteur ; suite complète 466 passed, 3 skipped.

Décision à prendre

Phases 4 à 7 suspendues. Options : tester l'intraday (données payantes), arrêter la méthode, ou revenir à une base passive.

🤖 Generated with Claude Code

…e (phase 3, F-46) : FAIL

- src/pullback/market.py : matrices float32 + pré-filtre vectorisé identique à
  rules.detect_consolidation (0 écart sur 12 089 contrôles réels) et au screener momentum.
- src/pullback/portfolio.py : moteur événementiel OHLC (gaps payés, pire cas intrajournalier,
  stop avant cible, frais, change EUR/USD, impôt annuel) ; modes d'ordre intrajournalier en sensibilité.
- src/pullback/bench.py : 6 variantes pré-enregistrées, walk-forward 2015-2020 / 2021+, contrôles hasard
  (40 tirages) et momentum seul, bootstrap, Sharpe déflaté, verdict calculé, rapport généré.
- docs/BACKTEST_PULLBACK_2026-10-12.md : test 2021-2026 -22,6 %/an, Sharpe -1,93, espérance -0,55 R,
  battu par le hasard ; B&H Nasdaq-100 EUR +14,6 %/an. Porte du plan non franchie.
- 15 tests moteur ; suite complète 466 passed, 3 skipped. Ne touche ni t212_executor.py ni schedule.py.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

@kilo-code-bot kilo-code-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Phase 3 pullback gate review. Inline findings below; no logic/numerical bugs found in the engine, prefilter, bench, or gate.

Comment thread src/pullback/bench.py
import logging
import math
import pickle
from dataclasses import dataclass, replace

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

WARNING: Unused import replace from dataclasses

replace is imported at src/pullback/bench.py:15 but is never referenced in the new file (the tests build frozen Variant instances via the keyword constructor, e.g. bench.Variant("b", max_dist=0.04), rather than dataclasses.replace). Under the repo's Ruff configuration in pyproject.toml, whose default rule set includes F401, ruff check flags this — remove it before merge.

Suggested change
from dataclasses import dataclass, replace
from dataclasses import dataclass

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

Comment thread src/pullback/bench.py
# 4) sous-univers très liquide (proxy partiel du biais du survivant)
Bl = Bench(mkt, refs, sig_large)
Bl.liquid = mkt.liquid(min_dollar_volume=LARGE_CAP_DOLLAR_VOLUME)
large, _ = Bl.evaluate(best, TEST_START, last)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

SUGGESTION: Dead assignment to Bl.liquid

Bl = Bench(mkt, refs, sig_large) is only driven through Bl.evaluate(...), which calls build_orders/run_portfolio — neither reads Market.liquid. Market.liquid is consumed only by Bench.ranks() (via momentum_masks); Bl.ranks() is never called in run_bench, so this assignment has no effect on the verdict. The large-cap filter is already applied at signal generation (market.candidate_setups(mkt, mkt.liquid(min_dollar_volume=LARGE_CAP_DOLLAR_VOLUME), ...)), so the line is misleading. Remove it, or keep it with a note if Bl.ranks() is intended later (note: removing is safe only while ranks() stays uncalled on Bl).


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Code Review Summary

Status: 2 Issues Found | Recommendation: Address minor non-behavioral issues before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 1

The pullback bench is a careful, well-tested (466 passed, 3 skipped) implementation of the daily pullback method and correctly computes the FAIL verdict from the plan gate (§2.1). I read the three new modules in full plus their dependencies (src/pullback/rules.py, store.py, universe.py; src/backtest/engine.py, metrics.py, strategies.py) and traced the timing, position-sizing units, tax/fee accounting, R-denominator consistency, gate/p-value logic, and reference-metrics keys. No logic or numerical bugs were found in the execution engine, the vectorized consolidation prefilter, the bench/walk-forward logic, or the gate. Two non-impacting cleanliness items are flagged inline.

Issue Details (click to expand)

WARNING

File Line Issue
src/pullback/bench.py 15 Unused import replace (from dataclasses) — flagged by Ruff F401 under the project's configured Ruff rules.

SUGGESTION

File Line Issue
src/pullback/bench.py 312 Dead assignment Bl.liquid = mkt.liquid(...): Bl.ranks() is never called, so .liquid is never read for Bl; the large-cap universe is already applied via sig_large at signal generation.
Files Reviewed (7 files)
  • src/pullback/bench.py — 2 issues (new)
  • src/pullback/market.py — 0 issues (new)
  • src/pullback/portfolio.py — 0 issues (new)
  • tests/test_pullback_portfolio.py — 0 issues (new)
  • src/pullback/rules.py — read for context (unchanged)
  • src/backtest/engine.py — read for context (unchanged)
  • src/backtest/metrics.py — read for context (unchanged)

Reviewed by free · Input: 312.6K · Output: 61.9K · Cached: 1.2M

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.

1 participant