"""TGTC pre-screen: filter Yahoo snapshot candidates using prior-day enrichment.""" from __future__ import annotations import logging from libs.tgtc.domain import TGTCFilterParams log = logging.getLogger(__name__) def pre_screen_candidates( enrichment: dict[str, dict], filters: TGTCFilterParams, ) -> set[str]: """Phase 1 pre-screen using prior-day enrichment (no intraday data). Args: enrichment: {symbol: {atr_14, avg_dollar_vol_30d, prev_close, ...}} filters: TGTCFilterParams instance Returns: Set of symbols passing the pre-screen. """ passed: set[str] = set() for sym, enr in enrichment.items(): prev_close = enr.get("prev_close") or 0.0 if prev_close < filters.min_price: continue avg_dv = enr.get("avg_dollar_vol_30d") or enr.get("avg_dollar_vol_20d") or 0.0 if avg_dv < filters.min_avg_dollar_volume_20d: continue passed.add(sym) log.debug("TGTC pre-screen: %d/%d passed", len(passed), len(enrichment)) return passed def apply_10am_hard_filters( candidates: list[dict], filters: TGTCFilterParams, ) -> list[dict]: """Phase 2 hard filters applied at 10:00 ET using intraday data. candidates: list of dicts with keys: symbol, pct_change_at_10, price_at_10, vwap_at_10, above_vwap, hod_at_10, avg_dv, market_cap (optional) Returns filtered list. """ out = [] for c in candidates: price = c.get("price_at_10", 0.0) or 0.0 pct = c.get("pct_change_at_10", 0.0) or 0.0 above_vwap = c.get("above_vwap", False) hod = c.get("hod_at_10", price) or price avg_dv = c.get("avg_dv", 0.0) or 0.0 market_cap = c.get("market_cap") if price < filters.min_price: continue if pct < filters.min_day_change_at_10 or pct > filters.max_day_change_at_10: continue if filters.must_be_above_vwap and not above_vwap: continue if market_cap is not None and market_cap < filters.min_market_cap: continue elif market_cap is None and avg_dv < filters.min_avg_dollar_volume_20d: continue if hod > 0 and price > 0 and (hod - price) / hod > filters.max_pullback_from_hod: continue out.append(c) return out