DuckDB + Parquet recipes for Valuein
7 query patterns for the questions analysts and quants ask first. Each one runs as written on the free sample, through the Python SDK or in plain DuckDB. Change the ticker and run.
Before you start
The recipes use table names (fact, "references", …). With the Python SDK those tables are already views, so a recipe runs unchanged in client.run_query(). In plain DuckDB, download the files from the Bulk Data API and create one view per table.
from valuein_sdk import ValueinClient sql = """SELECT symbol, name FROM "references" WHERE is_active LIMIT 5;""" # or any recipe below with ValueinClient() as client: # no key: the free sample print(client.run_query(sql)) # every table is already a view: no setup-- Plain DuckDB: download each table once. The sample tier needs no token:-- curl -o fact.parquet https://data.valuein.biz/v1/sample/fact-- then give each file a view named after its table, so the recipes run as written.CREATE VIEW fact AS SELECT * FROM read_parquet('fact.parquet');CREATE VIEW "references" AS SELECT * FROM read_parquet('references.parquet');CREATE VIEW index_membership AS SELECT * FROM read_parquet('index_membership.parquet');Start every cross-company query with `references`
`references` is entity joined to security: one row per listing with `cik`, `symbol`, `name`, `sector`. Filter `is_active AND is_primary_ticker` for one row per company today.
Why this works ↓Hide details ↑
`references` saves you joining `entity` and `security` yourself. A company can have several rows (share classes, retired tickers), so `is_active` keeps tickers in use today and `is_primary_ticker` keeps one per company. Index membership lives in `index_membership`, keyed on `cik`; there is no `is_sp500` flag. `references` is a reserved word in DuckDB, so always quote it.
SELECT r.symbol, r.name, r.sector, r.industryFROM "references" rJOIN index_membership im ON im.cik = r.cikWHERE im.index_name = 'SP500' AND im.removal_date IS NULL -- current member AND r.is_active -- a ticker in use today AND r.is_primary_ticker -- one row per companyORDER BY r.sector, r.symbol;Note · Use this as the spine of any screen, peer search or universe.
Latest annual value per company with LATERAL
A LATERAL subquery picks one row per company. `fact` keys on `entity_id`, which equals `references.cik`; it has no ticker column.
Why this works ↓Hide details ↑
Pulling every row and deduplicating in pandas is slow and easy to get wrong. LATERAL runs the inner query once per company and stops at LIMIT 1. Sorting by `period_end` then `accepted_at` takes the latest period and, within it, the latest filed value.
WITH members AS ( SELECT r.cik, r.symbol, r.sector FROM "references" r JOIN index_membership im ON im.cik = r.cik WHERE im.index_name = 'SP500' AND im.removal_date IS NULL AND r.is_active AND r.is_primary_ticker)SELECT m.symbol, m.sector, f.period_end, f.numeric_value AS revenueFROM members m,LATERAL ( SELECT f0.period_end, f0.numeric_value FROM fact f0 WHERE f0.entity_id = m.cik AND f0.standard_concept = 'TotalRevenue' AND f0.fiscal_period = 'FY' ORDER BY f0.period_end DESC, f0.accepted_at DESC LIMIT 1) fORDER BY revenue DESC NULLS LASTLIMIT 25;Note · LATERAL is much cheaper than a self-join on `fact`.
Pivot several concepts in one pass over `fact`
Deduplicate vintages first, then one MAX(CASE) pivot turns revenue, net income, EPS and operating cash flow into columns. Group by `period_end`.
Why this works ↓Hide details ↑
A 10-K repeats two or three earlier years as comparatives, so one period can appear in several filings. QUALIFY keeps the latest-filed value per (company, concept, period); without it MAX() would pick whichever vintage is largest. The pivot then reads `fact` once instead of once per concept.
WITH ids AS ( SELECT cik, symbol FROM "references" WHERE symbol IN ('AAPL', 'MSFT', 'GOOGL', 'NVDA') AND is_active AND is_primary_ticker),latest AS ( -- A 10-K repeats earlier years as comparatives: keep the -- latest-filed value for each (company, concept, period). SELECT fa.entity_id, fa.period_end, fa.standard_concept, fa.numeric_value FROM fact fa JOIN ids ON ids.cik = fa.entity_id WHERE fa.fiscal_period = 'FY' AND fa.standard_concept IN ('TotalRevenue', 'NetIncome', 'EPSDiluted', 'OperatingCashFlow') QUALIFY ROW_NUMBER() OVER ( PARTITION BY fa.entity_id, fa.standard_concept, fa.period_end ORDER BY fa.accepted_at DESC ) = 1)SELECT ids.symbol, l.period_end, MAX(CASE WHEN l.standard_concept = 'TotalRevenue' THEN l.numeric_value END) AS revenue, MAX(CASE WHEN l.standard_concept = 'NetIncome' THEN l.numeric_value END) AS net_income, MAX(CASE WHEN l.standard_concept = 'EPSDiluted' THEN l.numeric_value END) AS eps_diluted, MAX(CASE WHEN l.standard_concept = 'OperatingCashFlow' THEN l.numeric_value END) AS operating_cash_flowFROM latest lJOIN ids ON ids.cik = l.entity_idGROUP BY ids.symbol, l.period_endORDER BY ids.symbol, l.period_end;Note · Each extra concept costs one more CASE, not one more scan.
Keep the latest vintage with QUALIFY ROW_NUMBER()
QUALIFY ROW_NUMBER() keeps one row per period: the most recently accepted value. `value_as_filed` and `restated` show what changed since the first filing.
Why this works ↓Hide details ↑
Every filing that reports a period adds a row; nothing is overwritten. QUALIFY is the cleanest way to keep the latest one. `numeric_value` is the value in that filing, `value_as_filed` the value first reported for the period, and `restated` is true when they differ.
WITH tsla AS ( SELECT cik FROM "references" WHERE symbol = 'TSLA' AND is_active AND is_primary_ticker)SELECT fa.period_end, fa.fiscal_period, fa.numeric_value, fa.value_as_filed, fa.restated, fa.accepted_atFROM fact faJOIN tsla ON tsla.cik = fa.entity_idWHERE fa.standard_concept = 'NetIncome'QUALIFY ROW_NUMBER() OVER ( PARTITION BY fa.entity_id, fa.period_end, fa.fiscal_period ORDER BY fa.accepted_at DESC) = 1ORDER BY fa.period_end DESC, fa.fiscal_period;| Metric | as reported | restated |
|---|---|---|
| Revenue | 10,388 | 10,388 |
| Operating income | 2,114 | 1,902 |
| Net income | 1,640 | 1,431 |
| Diluted EPS | 3.05 | 2.66 |
verify_fact_lineage() → both versions retained · each keyed to its filing
Note · Drop the QUALIFY clause to see every vintage of each period.
Quarter-only cash flow, Q4 included
Most Q2 and Q3 cash-flow rows are year-to-date as filed. `derived_quarterly_value` holds the quarter-only figure; on the FY row it is Q4.
Why this works ↓Hide details ↑
Companies usually report cash flow year-to-date in their 10-Qs, and there is no Q4 10-Q at all. The pipeline stores the quarter-only figure in `derived_quarterly_value`: equal to the filed value for a standalone quarter, the year-to-date difference otherwise, and on the FY row, Q4 (the year minus the first three quarters). `is_cumulative` tells you which rows were filed year-to-date.
WITH aapl AS ( SELECT cik FROM "references" WHERE symbol = 'AAPL' AND is_active AND is_primary_ticker)SELECT fa.period_end, fa.fiscal_period, fa.is_cumulative, -- TRUE = year-to-date as filed fa.numeric_value AS as_filed, COALESCE(fa.derived_quarterly_value, fa.numeric_value) AS quarter_onlyFROM fact faJOIN aapl ON aapl.cik = fa.entity_idWHERE fa.standard_concept = 'OperatingCashFlow' AND fa.fiscal_period IN ('Q1', 'Q2', 'Q3', 'FY') -- FY row carries Q4 AND (fa.fiscal_period <> 'FY' OR fa.derived_quarterly_value IS NOT NULL)QUALIFY ROW_NUMBER() OVER ( PARTITION BY fa.period_end, fa.fiscal_period ORDER BY fa.accepted_at DESC) = 1ORDER BY fa.period_end;Note · COALESCE falls back to `numeric_value` for a standalone quarter. An FY row is kept only when it carries Q4, so a full-year total never poses as a quarter.
Point-in-time screen: the universe and the data on a date
Filter `index_membership` by its effective and removal dates and `fact` by `accepted_at`, so both the company list and its numbers are what was known on that date.
Why this works ↓Hide details ↑
A backtest needs the index as it stood on the trade date, not today's members, and only the numbers already filed. Membership windows are half-open: a company removed on a date is not a member on it. With the Python SDK you can also pass `ValueinClient(as_of=...)`, which applies the `accepted_at` filter to every point-in-time table for you.
WITH universe_at AS ( -- S&P 500 members on 2024-01-02. Removal is exclusive: -- a company removed on that date is no longer a member. SELECT DISTINCT im.cik FROM index_membership im WHERE im.index_name = 'SP500' AND im.effective_date <= DATE '2024-01-02' AND (im.removal_date IS NULL OR im.removal_date > DATE '2024-01-02')),known AS ( -- Fiscal years that ended in 2022, using only values the SEC had -- accepted before 2024-01-02 (later restatements are ignored). SELECT fa.entity_id, fa.standard_concept, fa.numeric_value FROM fact fa WHERE fa.accepted_at < TIMESTAMP '2024-01-02 00:00:00' AND fa.fiscal_period = 'FY' AND fa.period_end BETWEEN DATE '2022-01-01' AND DATE '2022-12-31' AND fa.standard_concept IN ('TotalRevenue', 'NetIncome') QUALIFY ROW_NUMBER() OVER ( PARTITION BY fa.entity_id, fa.standard_concept ORDER BY fa.accepted_at DESC ) = 1)SELECT u.cik, MAX(CASE WHEN k.standard_concept = 'TotalRevenue' THEN k.numeric_value END) AS revenue, MAX(CASE WHEN k.standard_concept = 'NetIncome' THEN k.numeric_value END) AS net_income, net_income / NULLIF(revenue, 0) AS net_marginFROM universe_at uJOIN known k ON k.entity_id = u.cikGROUP BY u.cikORDER BY revenue DESC NULLS LASTLIMIT 50;Enron Corp
ENRNQ
bankrupt2001
Lehman Brothers
LEH
bankrupt2008
Bear Stearns
BSC
acquired2008
Countrywide Financial
CFC
acquired2008
Blockbuster Inc
BLOAQ
bankrupt2010
Whole Foods
WFM
acquired2017
Sears Holdings
SHLD
bankrupt2018
Twitter Inc
TWTR
taken private2022
SVB Financial
SIVB
failed2023
get_pit_universe(date) returns the market as it stood on that date, not as it survived.
Note · The membership filter prevents survivorship bias; the accepted_at filter prevents look-ahead bias. Join `references` on `cik` for today's ticker.
Defensive ratio math: ABS and NULLIF
Wrap capex in ABS (filers disagree on its sign) and every divisor in NULLIF (a zero divisor becomes NULL instead of an error).
Why this works ↓Hide details ↑
Some filers report capex as a negative cash flow and some as a positive amount, and some periods have zero revenue. ABS and NULLIF make the formula safe for all of them.
WITH ids AS ( SELECT cik, symbol FROM "references" WHERE symbol IN ('AAPL', 'MSFT', 'GOOGL', 'META', 'WMT', 'COST') AND is_active AND is_primary_ticker),latest AS ( SELECT fa.entity_id, fa.standard_concept, fa.numeric_value FROM fact fa JOIN ids ON ids.cik = fa.entity_id WHERE fa.fiscal_period = 'FY' AND fa.standard_concept IN ('TotalRevenue', 'OperatingCashFlow', 'CAPEX') QUALIFY ROW_NUMBER() OVER ( PARTITION BY fa.entity_id, fa.standard_concept ORDER BY fa.period_end DESC, fa.accepted_at DESC ) = 1),pivoted AS ( SELECT ids.symbol, MAX(CASE WHEN l.standard_concept = 'TotalRevenue' THEN l.numeric_value END) AS revenue, MAX(CASE WHEN l.standard_concept = 'OperatingCashFlow' THEN l.numeric_value END) AS ocf, MAX(CASE WHEN l.standard_concept = 'CAPEX' THEN l.numeric_value END) AS capex FROM latest l JOIN ids ON ids.cik = l.entity_id GROUP BY ids.symbol)SELECT symbol, ocf, capex, -- ABS: filers disagree on the sign of capex. -- NULLIF: a zero divisor returns NULL instead of failing the row. ocf - ABS(capex) AS free_cash_flow, (ocf - ABS(capex)) / NULLIF(revenue, 0) AS fcf_marginFROM pivotedORDER BY fcf_margin DESC NULLS LAST;Note · A missing input yields NULL rather than a wrong number; check the inputs when a ratio is NULL.
More patterns?
The Python SDK ships named SQL templates for common workflows: fundamentals by ticker, margins, free cash flow, factor screens, peer comparisons, filing links. client.list_templates() lists them all.