From 04bdc1737f8863b9caf757f9f21d966cf2818535 Mon Sep 17 00:00:00 2001 From: Harwinder Sekhon Date: Sun, 6 Sep 2026 16:55:26 -0400 Subject: [PATCH] signal_aggregator + chart_patterns: drop dead parameters and shadowed literals (no behaviour change) - analyze_pair(context=...): no caller ever supplied it (main, telegram_bot, pair_signals, tests), so the value was always None; the parameter and the pass-through to analyze_from_dataframes go (analyze_from_dataframes keeps its own context parameter). - The three specific "SELL FILTER: quality|volatility|regime" stale-prefix entries were shadowed by the general "SELL FILTER: " entry in the same startswith() tuple; every emitter carries the general prefix. - chart_patterns: the detectors never read the Open series, so the `o` parameter is dropped from the three detectors, the PATTERN_DETECTORS lambdas and the dispatcher. - Corrected the pb_funnel/cp_funnel comment: nothing reads those counters (the "read by backtest tooling" claim was stale); they stay as cheap diagnostics. Parity: 12-month M5 and H1 books regenerated byte-identical (md5 a28fed4becd056466c26d6a947e1a0e5 / d20405ef64f069770c258bb9bed1ac90). Suite: 461 passed, 0 failed. Claude-Session: https://claude.ai/code/session_0156YhogLytzj9P2iH1skGbL --- chart_patterns.py | 21 ++++++++++----------- signal_aggregator.py | 10 +++------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/chart_patterns.py b/chart_patterns.py index 9d0b72f..b42161f 100644 --- a/chart_patterns.py +++ b/chart_patterns.py @@ -97,7 +97,7 @@ def _first_close_beyond(closes: np.ndarray, start: int, level: float, # ── Double bottom / top ────────────────────────────────────────────── -def _detect_double(o, h, l, c, atr, cfg, bullish: bool) -> Optional[Dict]: +def _detect_double(h, l, c, atr, cfg, bullish: bool) -> Optional[Dict]: w = cfg.cp_swing_window ext = l if bullish else h idx = _swing_indices(ext, w, find_high=not bullish) @@ -147,7 +147,7 @@ def _detect_double(o, h, l, c, atr, cfg, bullish: bool) -> Optional[Dict]: # ── Head & shoulders (top and inverse) ─────────────────────────────── -def _detect_hs(o, h, l, c, atr, cfg, bullish: bool) -> Optional[Dict]: +def _detect_hs(h, l, c, atr, cfg, bullish: bool) -> Optional[Dict]: """bullish=True → inverse H&S (three swing LOWS, head deepest).""" w = cfg.cp_swing_window ext = l if bullish else h @@ -210,7 +210,7 @@ def _detect_hs(o, h, l, c, atr, cfg, bullish: bool) -> Optional[Dict]: # ── Flags (bull and bear) ──────────────────────────────────────────── -def _detect_flag(o, h, l, c, atr, cfg, bullish: bool) -> Optional[Dict]: +def _detect_flag(h, l, c, atr, cfg, bullish: bool) -> Optional[Dict]: n = len(c) lo_r, hi_r = cfg.cp_flag_retrace if bullish: @@ -257,12 +257,12 @@ def _detect_flag(o, h, l, c, atr, cfg, bullish: bool) -> Optional[Dict]: # Priority order: most structured / rarest first — if two patterns # complete on the same bar, the more specific one names the trade. PATTERN_DETECTORS = { - "inv_hs": lambda o, h, l, c, atr, cfg: _detect_hs(o, h, l, c, atr, cfg, True), - "hs_top": lambda o, h, l, c, atr, cfg: _detect_hs(o, h, l, c, atr, cfg, False), - "double_bottom": lambda o, h, l, c, atr, cfg: _detect_double(o, h, l, c, atr, cfg, True), - "double_top": lambda o, h, l, c, atr, cfg: _detect_double(o, h, l, c, atr, cfg, False), - "bull_flag": lambda o, h, l, c, atr, cfg: _detect_flag(o, h, l, c, atr, cfg, True), - "bear_flag": lambda o, h, l, c, atr, cfg: _detect_flag(o, h, l, c, atr, cfg, False), + "inv_hs": lambda h, l, c, atr, cfg: _detect_hs(h, l, c, atr, cfg, True), + "hs_top": lambda h, l, c, atr, cfg: _detect_hs(h, l, c, atr, cfg, False), + "double_bottom": lambda h, l, c, atr, cfg: _detect_double(h, l, c, atr, cfg, True), + "double_top": lambda h, l, c, atr, cfg: _detect_double(h, l, c, atr, cfg, False), + "bull_flag": lambda h, l, c, atr, cfg: _detect_flag(h, l, c, atr, cfg, True), + "bear_flag": lambda h, l, c, atr, cfg: _detect_flag(h, l, c, atr, cfg, False), } @@ -276,7 +276,6 @@ def detect_chart_pattern(df: pd.DataFrame, atr: float, cfg) -> Optional[Dict]: if atr <= 0 or len(df) < cfg.cp_lookback + 1: return None tail = df.iloc[-(cfg.cp_lookback + 1):] - o = tail["Open"].to_numpy(dtype=np.float64) h = tail["High"].to_numpy(dtype=np.float64) l = tail["Low"].to_numpy(dtype=np.float64) c = tail["Close"].to_numpy(dtype=np.float64) @@ -284,7 +283,7 @@ def detect_chart_pattern(df: pd.DataFrame, atr: float, cfg) -> Optional[Dict]: for name, det in PATTERN_DETECTORS.items(): if name not in enabled: continue - hit = det(o, h, l, c, atr, cfg) + hit = det(h, l, c, atr, cfg) if hit is not None: return hit return None diff --git a/signal_aggregator.py b/signal_aggregator.py index 2bfe558..25f40c3 100755 --- a/signal_aggregator.py +++ b/signal_aggregator.py @@ -150,8 +150,9 @@ class SignalReport: class SignalAggregator: """Master aggregator for live signal analysis.""" - # Diagnostic funnel for the M5 pullback route (shared across - # instances; read by backtest tooling, harmless in live use). + # Diagnostic rejection counters for the M5 pullback route (class-level, + # shared across instances). Nothing in the repo reads them; they are + # cheap and kept for ad-hoc inspection from a REPL. pb_funnel: Dict[str, int] = {} # Same, for the chart-pattern route (XAU_CP). cp_funnel: Dict[str, int] = {} @@ -172,7 +173,6 @@ class SignalAggregator: def analyze_pair( self, symbol: Optional[str] = None, - context: Optional[FundamentalContext] = None, log_source: Optional[str] = None, ) -> SignalReport: """Live-mode entry: fetch all needed timeframes then delegate. @@ -244,7 +244,6 @@ class SignalAggregator: report = self.analyze_from_dataframes( symbol=symbol, dfs=dfs, - context=context, use_news=True, ) @@ -919,9 +918,6 @@ class SignalAggregator: "EXHAUSTION BLOCK", "EXHAUSTED TREND FILTER:", "MTF OPPOSITION:", - "SELL FILTER: quality", - "SELL FILTER: volatility", - "SELL FILTER: regime", "SELL FILTER: ", "M5 FILTER: |score|", "M5 FILTER: no MTF agreement",