--- name: hfmd-fundamentals-screen description: Screen US stocks on fundamental ratios with HF Market Data (PE, PB, EV/EBITDA, FCF yield, ROE, margins, leverage, growth), enrich the hits with their latest ratios and recent quarterly statements, and document the point-in-time caveats (filing dates, restatements). Use when the user asks to "find stocks with…", "screen for…", or compare companies on fundamentals. --- # hfmd-fundamentals-screen Run a screener → pull ratios and statements for the survivors → produce a table the user can defend, with the date each number became public. ## When to use - "Screen US stocks with PE<15 and FCF yield>6% and show their last 3 quarters" - "Cheapest software companies by EV/EBITDA with ROE > 20 %", "which of these tickers has the best balance sheet?" - Historical: "what would this screen have returned on 2020-03-20?" (`--as-of`, point-in-time) ## Filter syntax `filters="pe<15,roe>0.15,fcf_yield>0.06,market_cap>1e9"` — comma-separated `metricvalue`, ops `< <= > >= =`. Ratios are **decimals** (0.15 = 15 %). Known metrics: `pe pb ps ev_ebitda fcf_yield dividend_yield roe roa gross_margin operating_margin net_margin debt_to_equity current_ratio revenue_growth eps_growth market_cap sector`. Sort: `--sort fcf_yield:desc`. ## Steps 1. Translate the request into filters (ask for thresholds when vague: "cheap" → `pe<15`? `ev_ebitda<8`?). Convert percentages to decimals. 2. Screen + enrich: `python3 scripts/screen.py --filters "pe<15,fcf_yield>0.06" --sort fcf_yield:desc --limit 25 --quarters 3 --out screen.csv` - calls `/v1/fundamentals/screener` (cost: 2 requests), then for each hit `/v1/fundamentals/{t}/ratios` and `/v1/fundamentals/{t}/statements?statement=income&period=quarterly&limit=3` (`--no-enrich` to skip; keyless quota allows ~10 tickers/hour — set `HFMD_API_KEY`). - prints the screen table, then per ticker the last N quarters (revenue, operating income, net income, EPS, filed_at) and a **point-in-time note**: latest `filed_at` used, days since, whether a newer period end exists without a filing yet. 3. Present: one table sorted as requested, then the quarterly mini-tables, then caveats. ## Point-in-time discipline (always say it) - Every fundamentals row carries `period_end` **and** `filed_at`. A number is knowable only from `filed_at` (10-Q ≈ 40 days, 10-K ≈ 60-90 days after period end). Screens with `--as-of` use what was filed by that date — this is what makes a backtest of the screen honest. - Restatements: `facts/{concept}` returns every reported value for a period; the statements endpoint returns the latest. Mention it when a number looks off. - Price-based ratios (PE, FCF yield…) use the close of `as_of` (or the latest) and the last **reported** TTM figures — not analyst estimates. - Coverage differs by company (`/v1/fundamentals/{t}/coverage`): small caps and recent IPOs have short histories; missing = `null`, never imputed. ## Examples ```bash # Classic value + quality python3 scripts/screen.py --filters "pe<15,roe>0.15,debt_to_equity<1" --sort pe:asc --limit 20 # Point-in-time: what the screen showed at the March 2020 low python3 scripts/screen.py --filters "fcf_yield>0.08,net_margin>0.1" --as-of 2020-03-20 --no-enrich # Only enrich a list you already have python3 scripts/screen.py --tickers AAPL MSFT GOOGL --quarters 4 ``` ## Gotchas - A screener 404 means the fundamentals module is not deployed yet on the server; the script says so and exits 2. - `sector` is a string filter (`sector=Technology`); everything else is numeric. - Banks/insurers: EV/EBITDA and FCF yield are not meaningful — prefer PB, ROE. - The screener costs 2 quota requests; with 30/h keyless, do not loop over many parameter sets without a key.