You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

74 lines
2.3 KiB
Python

"""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