#!/usr/bin/env python3 """GARP scan - batch download approach for speed.""" import yfinance as yf import json, sys sys.stdout.reconfigure(line_buffering=True) EXCLUDE = {"BAC", "CFG", "FITB", "INCY"} with open("broad_tickers.txt") as f: tickers = [l.strip().replace(".", "-") for l in f if l.strip()] print(f"Screening {len(tickers)} tickers in batches...") passed = [] batch_size = 20 for batch_start in range(0, len(tickers), batch_size): batch = tickers[batch_start:batch_start + batch_size] batch = [t for t in batch if t not in EXCLUDE] if not batch: continue print(f"Batch {batch_start}-{batch_start+len(batch)} / {len(tickers)}...") try: data = yf.Tickers(" ".join(batch)) for tick in batch: try: info = data.tickers[tick].info or {} mc = info.get("marketCap", 0) or 0 if mc < 5e9: continue tpe = info.get("trailingPE") if not tpe or tpe >= 25 or tpe <= 0: continue fpe = info.get("forwardPE") if not fpe or fpe >= 15 or fpe <= 0: continue rg = info.get("revenueGrowth") if rg is None or rg < 0.10: continue eg = info.get("earningsGrowth") if eg is None or eg < 0.15: continue roe = info.get("returnOnEquity") if roe is None or roe < 0.05: continue peg = info.get("pegRatio") if peg is not None and peg > 1.2: continue dte = info.get("debtToEquity") if dte is not None and dte > 35: continue entry = { "ticker": tick, "name": info.get("longName", tick), "market_cap_B": round(mc / 1e9, 1), "trailing_pe": round(tpe, 2), "forward_pe": round(fpe, 2), "peg": round(peg, 2) if peg else None, "revenue_growth_pct": round(rg * 100, 1), "earnings_growth_pct": round(eg * 100, 1), "roe_pct": round(roe * 100, 1), "debt_to_equity": round(dte, 1) if dte else None, "sector": info.get("sector"), "industry": info.get("industry"), } passed.append(entry) print(f" ✅ {tick}: PE={tpe:.1f} FPE={fpe:.1f} RG={rg*100:.0f}% EG={eg*100:.0f}% ROE={roe*100:.0f}%") except: continue except Exception as e: print(f" Batch error: {e}") continue passed.sort(key=lambda x: x.get("forward_pe", 99)) with open("garp-expanded-scan.json", "w") as f: json.dump(passed, f, indent=2) print(f"\nDone! {len(passed)} stocks passed GARP screen") for s in passed: print(f" {s['ticker']:6s} ${s['market_cap_B']:6.1f}B PE:{s['trailing_pe']:5.1f} FPE:{s['forward_pe']:5.1f} RG:{s['revenue_growth_pct']:5.1f}% EG:{s['earnings_growth_pct']:5.1f}% ROE:{s['roe_pct']:5.1f}%")