SPB Git forge

spb/hfmarketdata

Public

Open high-frequency market data platform — FirstRate full-history downloader, DuckDB/Parquet lake, open REST API and React docs platform (www.hfmarketdata.io)

127commits 1branches 0releases
24.7 MBsize
maindefault branch
11 days agolast push
JavaScript 53.7% Python 38.3% CSS 4.6% TypeScript 3.1%

# 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

  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.