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 metric<op>value, 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
- Translate the request into filters (ask for thresholds when vague: "cheap" →
pe<15?ev_ebitda<8?). Convert percentages to decimals. - 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}/ratiosand/v1/fundamentals/{t}/statements?statement=income&period=quarterly&limit=3(--no-enrichto skip; keyless quota allows ~10 tickers/hour — setHFMD_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_atused, days since, whether a newer period end exists without a filing yet.
- calls
- 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_endandfiled_at. A number is knowable only fromfiled_at(10-Q ≈ 40 days, 10-K ≈ 60-90 days after period end). Screens with--as-ofuse 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 4Gotchas
- A screener 404 means the fundamentals module is not deployed yet on the server; the script says so and exits 2.
sectoris 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.