valuein-sdk
Point-in-time, survivorship-free SEC EDGAR fundamentals for Python.
valuein-sdk gives you standardized financial statements from SEC filings back to
1993, queried with SQL in an in-process DuckDB. Every query sees only what was public
at your as_of date: rows are filtered on accepted_at, the moment the SEC accepted
the filing. Delisted, acquired and bankrupt companies stay in the data, and index
membership is stored as historical spells, so a universe on a past date is the one that
existed then. Every fact carries a fact_id and the accession number of the filing it
came from, so any number can be traced back to its source document.
Documentation · Examples · SQL cookbook · Schema · Pricing
Install
pip install valuein-sdk
Python 3.10 or newer. Optional extras:
| Extra | Adds |
|---|---|
valuein-sdk[polars] |
client.to_polars() and PriceQuery.to_polars() |
valuein-sdk[research] |
NumPy, Matplotlib and a Jupyter kernel for notebooks |
valuein-sdk[otel] |
OpenTelemetry spans (emitted only if your app configures a tracer) |
valuein-sdk[all] |
polars, otel, NumPy and Matplotlib |
Quickstart: 30 seconds, no token
With no API key the client runs on the free sample tier: S&P 500 constituents over the last five years. There is nothing to sign up for.
from valuein_sdk import ValueinClient
with ValueinClient() as client: # no token: free sample tier
print(client.resolve("AAPL")) # ticker -> CIK, name, active flag
revenue = client.run_template(
"fundamentals_by_ticker",
ticker="AAPL",
form_types=["10-K"],
metrics=["TotalRevenue", "NetIncome"],
)
print(revenue.head())
resolve returns one row per identifier with cik, symbol, name, is_active,
valid_from, valid_to and matched_by. The template returns one row per fact:
filing_date, report_date, period_end, fiscal_period, standard_concept,
numeric_value, unit. A 10-K also carries prior-year comparatives, so use
period_end, not report_date, to tell which year a number belongs to.
The same data from the shell:
valuein query 'SELECT symbol, name, sector FROM "references" WHERE is_active LIMIT 5'
valuein doctor # plan, snapshot, tables and cache, with no secrets
To use your plan, set a token and run the same code:
export VALUEIN_API_KEY="your_token" # or put it in a .env file
Core ideas
| Idea | What it means in code |
|---|---|
| Point in time | ValueinClient(as_of=...) takes a timezone-aware datetime (default: now, UTC). Point-in-time tables are filtered to accepted_at <= as_of. If that filter cannot be applied, the SDK raises ValueinIntegrityError instead of returning unfiltered rows. |
| Restatements | A later filing that reports a period again adds new rows with their own accepted_at. Under an as_of you see what was public then. The ratio view keeps only the latest vintage per ratio and period as of the cutoff. |
| Survivorship-free | references and entity include inactive companies. index_membership stores each membership as a spell (effective_date, removal_date), so pit_universe(date) returns the index as it was on that date. |
| CIK over ticker | Every method that takes a ticker also takes a CIK ("0000320193", "320193" or 320193). A CIK never changes; a ticker can be retired and later reused by another company. |
| Traceable numbers | Each fact row has a fact_id (SHA-256 of entity_id, accession_id, concept, period_end, unit) and the accession_id of its SEC filing. FactRecord.verify() recomputes the hash; filing_links() gives the EDGAR URLs. |
| Local compute | Queries run in an in-process DuckDB over Parquet streamed from the Valuein gateway. Downloads are cached on disk. There is no database to set up. |
Recipes
Every recipe runs on the free sample tier unless its heading says otherwise.
Get fundamentals for a ticker as of a date
from datetime import datetime, timezone
from valuein_sdk import ValueinClient
as_of = datetime(2024, 6, 30, tzinfo=timezone.utc)
with ValueinClient(as_of=as_of) as client:
facts = client.read_table("fact", tickers="AAPL")
assert (facts["accepted_at"] <= as_of).all() # nothing from after the cutoff
annual_revenue = (
facts[(facts["standard_concept"] == "TotalRevenue") & (facts["fiscal_period"] == "FY")]
.sort_values("accepted_at")
.drop_duplicates("period_end", keep="last") # latest value known on as_of
.sort_values("period_end")
)
print(annual_revenue[["period_end", "numeric_value", "unit", "accepted_at", "fact_id"]])
read_table(table, tickers=...) fetches only that company's partition where the
gateway serves one, and applies the same as_of filter. For backtests use
numeric_value. With an explicit as_of (or a bundle), value_current, restated
and restatement_count are recomputed from the filings accepted by the cutoff;
value_as_filed is as exported. Without an explicit as_of they are the latest
export's values.
Screen a universe without survivorship bias
from datetime import datetime, timezone
from valuein_sdk import ValueinClient
as_of = datetime(2023, 6, 30, tzinfo=timezone.utc)
with ValueinClient(as_of=as_of) as client:
members = client.pit_universe("2023-06-30") # S&P 500 on that date
roe = client.run_query(
"""
SELECT entity_id AS cik, value AS roe, period_end
FROM ratio
WHERE ratio_name = 'return_on_equity'
AND fiscal_period = 'FY'
AND period_end >= DATE '2022-06-30' -- skip stale fiscal years
QUALIFY row_number() OVER (PARTITION BY entity_id ORDER BY period_end DESC) = 1
"""
)
screen = members.merge(roe, on="cik").nlargest(10, "roe")
print(screen[["cik", "ticker_at_date", "company_name", "roe", "period_end", "removal_date"]])
print("members later removed from the index:", members["removal_date"].notna().sum())
pit_universe returns one row per member with cik, company_name, ticker_at_date,
sector, industry, effective_date and removal_date. Companies that left the index
after the date are still members on it. The ratio table holds annual (fiscal_period = 'FY') and trailing-twelve-month ('TTM') rows: always filter on fiscal_period, or
each company appears twice.
Backtest a factor (Pro or Institutional)
The quant layer needs daily prices (stock_price_daily), which only the Pro and
Institutional plans carry.
from valuein_sdk import ValueinClient
with ValueinClient() as client: # reads VALUEIN_API_KEY
result = client.factor_backtest(
"return_on_equity", # a ratio_name, a factor_scores column, or "mom_12m"
start="2018-01-01",
end="2024-12-31",
freq="QE",
)
print(result.summary()) # net and gross results, with the execution lag and cost used
print(result.mean_ic, result.ic_ir) # rank information coefficient and its stability
print(result.quantile_summary()) # mean return per quantile
factor_backtest builds the universe at each rebalance date from index membership,
reads each signal value as of that date, prices trades with a one-day execution lag
(execution_lag=1) and charges 10 bps per unit traded (cost_bps=10.0). Positions in
companies that delist are truncated, not dropped, and the summary lists what the study
could not use. For a custom signal, run the three steps yourself:
from valuein_sdk import ValueinClient, backtest
with ValueinClient() as client:
universe = client.universe("SP500", start="2018-01-01", end="2024-12-31", freq="QE")
panel = client.signal_panel(universe, ratios=["return_on_equity", "debt_to_equity"])
panel = client.forward_returns(panel) # appends forward-return columns
panel["score"] = panel["return_on_equity"].rank(pct=True) - panel["debt_to_equity"].rank(pct=True)
result = backtest(panel, signal="score", quantiles=5, cost_bps=10.0)
print(result.summary())
From the shell: valuein backtest return_on_equity --start 2018-01-01 --end 2024-12-31 --freq QE. More recipes, including Monte Carlo and reproducible bundles, are in the
Python SDK docs.
Prices and total return
Every tier has stock_price: one close per company at each fiscal period end and each
completed month end, with the listing's total_return_index (splits and dividends
reinvested).
from valuein_sdk import ValueinClient
with ValueinClient() as client:
print(client.stock_price("AAPL")) # latest row
monthly = client.run_query(
"""
SELECT price_date, close, total_return_index
FROM stock_price
WHERE entity_id = '0000320193' AND observation = 'monthly'
ORDER BY price_date
"""
)
tri = monthly["total_return_index"]
print(f"12-month total return: {tri.iloc[-1] / tri.iloc[-13] - 1:.1%}")
Daily bars (stock_price_daily) are on Pro and Institutional:
from valuein_sdk import ValueinClient
with ValueinClient() as client:
bars = (
client.prices(["AAPL", "MSFT"])
.between("2024-01-01", None)
.fields("close", "total_return")
.to_pandas()
)
growth = client.total_return("AAPL", "2020-01-01", "2024-12-31") # a fraction
# one column per ticker
panel = client.price_panel(["AAPL", "MSFT"], "2024-01-01", "2024-12-31")
Use a total-return basis (total_return_index, or the total_return field, which is
the default) for return math. Raw close is not split-adjusted, and adding div_cash on
top of a total-return series counts dividends twice. stock_price_daily has one row per
security per day, so a company with two share classes has two rows per day; the SDK's
price methods pick one bar per company per day for you.
Run a SQL template
The package ships parameterized SQL templates for common analyses: margins, free cash flow, Piotroski and Altman inputs, DuPont, restatement history, filing delays and more.
from valuein_sdk import ValueinClient
with ValueinClient() as client:
print(client.list_templates())
fcf = client.run_template(
"free_cash_flow",
ticker="MSFT",
form_types=["10-K"],
start_date="2021-01-01",
end_date="2025-12-31",
)
print(fcf.head())
Pass parameters as keywords: run_template(name, **params). Every value is validated
and quoted before the SQL is rendered: tickers such as "BRK-B" (share classes take a
hyphen, as references spells them), XBRL
frames such as "CY2023", "CY2024Q1" or "CY2024Q1I", fiscal_period one of Q1
to Q4, FY or TTM, and min_rank a percentile from 0.0 to 1.0. Common
parameters you omit get defaults: form_types is ["10-K", "10-Q"], start_date five
years ago, end_date today, and fiscal_period is "FY" for a template that reads
ratio (otherwise "Q1").
Templates read the same point-in-time views as run_query. The smart-money templates
(insider_buys, blockholders, top_institutional_holders, manager_portfolio) need
Institutional; price_history, price_return and price_momentum_screen need Pro or
Institutional. Copy-paste SQL patterns are in the
SQL cookbook.
Raw SQL over the tables
from valuein_sdk import ValueinClient
with ValueinClient() as client:
current_members = client.run_query(
"""
SELECT r.cik, r.symbol, r.name, 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
ORDER BY r.symbol
"""
)
print(current_members.head())
- Tables mount on first use; a query can reference any table on your plan.
"references"is an SQL keyword: keep the double quotes.run_queryaccepts oneSELECT,WITHorEXPLAINstatement. Writes, file and network functions (read_parquet,glob, ...) and system catalogs are rejected.- Other outputs:
client.to_arrow(sql),client.to_polars(sql), andclient.stream(sql)for results too large to hold in memory. - Columns:
client.get_schema("fact"), or the schema reference.
Verify a number back to the SEC filing
from valuein_sdk import FactRecord, ValueinClient
with ValueinClient() as client:
facts = client.read_table("fact", tickers="AAPL")
row = (
facts[(facts["standard_concept"] == "TotalRevenue") & (facts["fiscal_period"] == "FY")]
.sort_values(["period_end", "accepted_at"])
.iloc[-1]
)
record = FactRecord.model_validate(row.to_dict())
assert record.verify() # fact_id matches the hash of its identity fields
links = client.filing_links("AAPL", form_types=["10-K"])
filing = links[links["accession_id"] == record.accession_id].iloc[0]
print(record.numeric_value, record.unit, record.period_end, record.fact_id)
print(filing["inline_viewer_url"] or filing["document_url"] or filing["sec_url"])
filing_links returns accession_id, form_type, filing_date, accepted_at and
four EDGAR URLs per filing: inline_viewer_url (the Inline XBRL viewer; None for older
filings), document_url, viewer_url and sec_url (the filing index, always present).
compute_fact_id(entity_id, accession_id, concept, period_end, unit) computes the same
hash as a plain function.
Track restatements
from valuein_sdk import ValueinClient
with ValueinClient() as client:
events = client.restatements(ticker="AAPL")
columns = ["period_end", "standard_concept", "first_value", "current_value", "disclosure_class"]
print(events[columns])
restatements() reads restatement_events on every tier, including with no token.
Each row is one reported value that a later filing changed, with both accession
numbers. disclosure_class is non_reliance (an 8-K Item 4.02 notice), amended (a
10-K/A or 10-Q/A) or undisclosed (the change appeared in a routine filing). Filter with
disclosure_class=, severity= and min_delta_pct=.
Plans and tiers
The SDK reads your plan from your token; your code does not change between plans. The same token unlocks the bulk data API, the MCP server and the Valuein Workspace at your plan.
| Plan | Key in code | How to get it | Coverage |
|---|---|---|---|
| Sample | sample |
No token | S&P 500 constituents, last five years |
| Benchmark | sp500 |
Free registration | Every S&P 500 constituent, full history |
| Pro | pro |
Paid | Full US universe, plus daily prices (stock_price_daily) |
| Institutional | full |
Paid | Pro, plus insider, 13F/13D/13G and Form ADV tables |
client.plan shows the active plan. get_plans() returns each plan's request rate
limits from the gateway. Prices and history windows: valuein.biz/pricing.
Tables
The table list and every column come from the gateway's manifest at runtime: use
client.tables() and client.get_schema(table), and client.manifest() for the
snapshot and schema version you are reading. "PIT" means the view is filtered to
accepted_at <= as_of.
| Table | What it holds | PIT | Plans |
|---|---|---|---|
references |
Start here. One row per security: cik, symbol, name, sector, industry, is_active, is_primary_ticker, FIGI identifiers |
All | |
entity |
Company master: addresses, SIC code, state of incorporation, former names | All | |
security |
Ticker history with valid_from / valid_to |
All | |
filing |
One row per SEC filing: accession_id, form_type, filing_date, report_date, accepted_at, primary_document |
Yes | All |
filing_registrant |
Every registrant of a filing (accession_id, entity_id). filing lists a co-registrant filing under one CIK; join this table to filing on accession_id to list a company's filings including the combined ones. The join to filing applies the point-in-time filter |
Where the plan's manifest lists it | |
fact |
Standardized financial facts: standard_concept, raw XBRL concept, numeric_value, unit, period_end, fiscal_period, accepted_at, fact_id, accession_id. priority = 1 marks the tag elected for its concept in a filing, decided at export by tag precedence |
Yes | All |
ratio |
Computed ratios by company and period: ratio_name, category, value, fiscal_period (FY or TTM). confidence_score is computed over the full export history and is not point-in-time under a past as_of |
Yes | All |
standard_concept |
Dictionary of the standardized concepts in fact.standard_concept |
All | |
taxonomy_guide |
Reference for the raw us-gaap tags in fact.concept |
All | |
index_membership |
Index membership spells keyed on cik: index_name, effective_date, removal_date (exclusive) |
All | |
factor_scores |
Cross-sectional factor scores and percentile ranks by company and period | Yes | All |
earnings_signals |
EPS trend estimate and surprise, revenue growth, price momentum | Yes | All |
stock_price |
Close and total_return_index at period ends and completed month ends |
Yes | All |
stock_price_daily |
Daily OHLCV bars, div_cash, split_factor, total_return_index, is_primary_listing |
Yes | Pro, Institutional |
restatement_events |
Values a later filing changed, with both accessions and a disclosure_class |
All | |
| Smart money | insider_party, insider_filing, insider_transaction, insider_ownership, institutional_filing, institutional_holding |
Yes, except insider_party |
Institutional |
| Form ADV | investment_adviser, investment_adviser_private_fund (keyed on CRD, not CIK) |
Institutional |
Join keys: fact.entity_id, filing.entity_id and security.entity_id hold the CIK;
fact.accession_id = filing.accession_id; index_membership.cik = "references".cik.
There is no is_sp500 column: join index_membership instead. For one quarter of a
cash-flow item use COALESCE(derived_quarterly_value, numeric_value), because Q2 and Q3
10-Qs report year-to-date figures.
API at a glance
Everything below imports from valuein_sdk. Every public method is typed and
documented: help(ValueinClient.read_table) shows the arguments, the returned columns
and the errors, and client.capabilities() returns the whole surface as a dictionary.
ValueinClient(as_of=None, api_key=None, gateway_url=None, tables=None, config=None)
| Method | Returns | Use it to |
|---|---|---|
| Read data | ||
read_table(table, *, columns=None, limit=None, tickers=None) |
DataFrame |
Read a table through its point-in-time view, optionally for some companies |
run_query(sql) |
DataFrame |
Run one read-only DuckDB query |
run_template(name, **params) |
DataFrame |
Run a packaged SQL template |
list_templates() |
list[str] |
List template names |
to_arrow(sql) / to_polars(sql) / stream(sql, batch_size=10_000) |
Arrow / Polars / iterator | Other output formats |
get(table) |
DataFrame |
Download the raw published table, without the as_of filter |
| Companies and universes | ||
resolve(identifiers) |
DataFrame |
See which company each ticker or CIK matches |
pit_universe(as_of_date, index="SP500") |
DataFrame |
Index members on a past date |
factor_scores(ticker=None, sector=None, min_composite_rank=None, limit=100) |
DataFrame |
Factor scores and ranks |
earnings_signals(ticker=None, min_surprise_pct=None, direction=None, limit=100) |
DataFrame |
EPS surprise and trend |
restatements(*, ticker=None, disclosure_class=None, severity=None, min_delta_pct=None, limit=100) |
DataFrame |
Restatement events |
filing_links(ticker, form_types=None, start_date=None, end_date=None, limit=20) |
DataFrame |
EDGAR URLs per filing |
| Prices | ||
stock_price(ticker, date=None) |
DataFrame |
Latest (or dated) close; every tier |
prices(tickers) |
PriceQuery |
Daily bars: .between(), .fields(), .last(), .to_pandas(); Pro+ |
total_return(ticker, start, end, *, basis="total_return") |
float |
Total return over a window; Pro+ |
price_panel(tickers, start, end, *, field="total_return") |
DataFrame |
Wide price matrix; Pro+ |
pit_panel(tickers, dates, *, concepts=None) |
DataFrame |
Price and fundamentals known by the end (UTC) of each date; flows as trailing twelve months; Pro+ |
pit_valuation_ratios(ticker, as_of) |
DataFrame |
P/E, P/S, P/B and EV/Revenue on a date, on trailing-twelve-month flows; Pro+ |
price_health() / corporate_actions(ticker) |
dict / DataFrame |
Price data coverage; splits and dividends; Pro+ |
| Quant research (Pro+) | ||
factor_backtest(signal, *, start, end, freq="ME", ...) |
BacktestResult |
Universe, signal, forward returns and backtest in one call |
universe(index_name="SP500", *, dates=None, start=None, end=None, freq="ME") |
DataFrame |
Index members at each rebalance date (dates= works on every tier) |
signal_panel(universe, *, ratios=, concepts=, factors=, momentum_months=) |
DataFrame |
Signal values accepted by the end (UTC) of each rebalance date; flow concepts (revenue, income, cash flow) as trailing twelve months |
forward_returns(panel, *, execution_lag=1) |
DataFrame |
Return to the next rebalance, delisting-aware |
trading_days(start, end) / rebalance_dates(start, end, freq=) |
DatetimeIndex / list[str] |
Calendars built from actual trading days |
write_bundle(path, *, tables, ...) / ValueinClient.from_bundle(path) |
BundleManifest / client |
Freeze a data slice with SHA-256 hashes; replay it offline |
| Session | ||
plan / as_of |
str / datetime |
Active plan and cutoff |
tables() / get_schema(table) |
list[str] / dict |
Tables on your plan; column types |
me() / manifest() / health() |
dict |
Token, snapshot and gateway status |
capabilities() / diagnostics() / usage() |
dict / dict / report |
Machine-readable surface; redacted support bundle; download budget |
cache_info() / clear_cache(*, table=None) |
dict |
On-disk cache |
report_issue(message, *, category="bug", ...) |
FeedbackReceipt |
Report a bug or a data problem; works with no token |
close() |
Release DuckDB and HTTP resources (or use with) |
|
| Deprecated (removed in 7.0) | Each emits a DeprecationWarning. For the file, use the Valuein Workspace or the MCP tool of the same name; for the numbers, compute locally with run_query() / get() (see the 10_dcf_valuation notebook). Pro+, token required |
|
generate_dcf_xlsx(ticker, *, as_of_date=None, depth="standard", stage1_growth_rate=None, wacc=None, terminal_growth_rate=None, stage1_years=None, dcf_result=None, company_name=None) |
dict |
DCF workbook rendered by the MCP server; runs compute_dcf first from stage1_growth_rate (or renders your dcf_result); as_of_date defaults to the client's as_of |
generate_comps_xlsx(ticker, *, peers=None, as_of_date=None, peer_rows=None, subject_company_name=None, notes=None) |
dict |
Peer-comparables workbook; peers from get_peer_comparables (or your peer_rows); as_of_date defaults to the client's as_of |
generate_research_brief_docx(ticker, *, as_of_date=None, depth="full", peers=None, title=None, sections=None, abstract=None, snapshot=None, citations=None, company_name=None, author_name=None) |
dict |
Typesets a brief you wrote (title and sections required) as a Word document |
Also exported: backtest, block_bootstrap, bootstrap, gbm and correlated_gbm
(every simulation requires a seed), AlphaEngine with built-in factors such as ROE
and GROSS_MARGIN, FactRecord, compute_fact_id, ValueinConfig and the
ValueinError hierarchy. valuein_sdk.aio.AsyncValueinClient is the asyncio client.
Command line
The valuein command installs with the package and uses the same token rules.
| Command | Does |
|---|---|
valuein doctor |
Print a redacted diagnostics bundle |
valuein tables |
List tables on your plan |
valuein schema TABLE |
Show a table's columns and types |
valuein query "SQL" [--format csv|json] |
Run a read-only query |
valuein prices TICKER [--start] [--end] [--last N] |
Daily bars (Pro+) |
valuein health [TICKERS...] |
Price data coverage (Pro+) |
valuein backtest SIGNAL --start --end [--freq] [--quantiles] [--cost-bps] ... |
Factor backtest (Pro+) |
valuein bundle PATH --tables T1 T2 ... |
Write an offline research bundle |
valuein cache stats / valuein cache clear [--table T] |
Inspect or clear the cache, offline |
Configuration
Environment variables
| Variable | Effect |
|---|---|
VALUEIN_API_KEY |
Your token, read when api_key is not passed. A .env file found from the current directory upward is loaded once per process. |
VALUEIN_NO_DOTENV |
1, true, yes or on (any case) skips loading .env; any other value, 0 included, loads it. |
VALUEIN_GATEWAY_URL |
Override the data gateway URL (development). |
VALUEIN_MCP_URL |
Override the MCP server URL used by report_issue() and the deprecated generate_* methods. |
VALUEIN_PLANS_ENDPOINT |
Override the URL that get_plans() reads. |
VALUEIN_DISABLE_TELEMETRY |
1 or true turns off OpenTelemetry spans. |
VALUEIN_DEBUG |
Make the CLI print full tracebacks. |
XDG_CACHE_HOME |
Cache root (default ~/.cache); the SDK uses valuein-sdk/ under it. |
api_key=None (the default) reads the environment, api_key="" forces the sample
tier, and any other string is used as the token.
ValueinConfig
from valuein_sdk import ValueinClient, ValueinConfig
config = ValueinConfig(memory_limit="8GB", threads=8, safe_mode=True)
with ValueinClient(config=config) as client:
print(client.run_query('SELECT count(*) AS n FROM "references"'))
| Field | Default | Meaning |
|---|---|---|
memory_limit |
"4GB" |
DuckDB memory ceiling; DuckDB spills to disk above it |
threads |
4 |
DuckDB threads |
temp_directory |
None |
Spill and download directory; None uses a temporary directory removed on close() |
max_temp_directory_size |
"20GB" |
Cap on spill-disk use |
connect_timeout / read_timeout |
30.0 / 120.0 |
HTTP timeouts in seconds |
cache_enabled / cache_dir / cache_max_bytes |
True / None / 4 GiB |
On-disk Parquet cache |
cache_revalidate |
True |
Check a cached file's ETag once per session; if the check cannot run, the cached copy is used |
safe_mode |
False |
Block DuckDB file and network access; use it when running SQL written by a model |
hot_data |
True |
Include filings published since the last weekly snapshot in filing, fact and ratio |
hot_index_ttl_s / hot_max_partitions |
60.0 / 200 |
How often to re-check for those filings; most companies folded in per table |
ValueinConfig is frozen: build a new one instead of changing a field.
Errors
Every SDK error subclasses ValueinError, and every message says what was wrong and how
to fix it.
| Exception | Raised when |
|---|---|
ValueinAuthError |
The token is invalid, expired or revoked |
ValueinPlanError |
The request needs a higher plan |
ValueinNotFoundError |
A table, ticker or CIK is not found, or is outside your plan's universe |
ValueinRateLimitError |
Too many requests; .retry_after holds seconds when the gateway sends it |
ValueinAPIError |
The gateway returned a 5xx; .status_code holds it |
ValueinConnectionError |
The gateway cannot be reached (also a ConnectionError) |
ValueinTimeoutError |
A request timed out after retries (also a TimeoutError) |
ValueinValidationError |
An argument, query or parameter is invalid (also a ValueError) |
ValueinDataError |
A query failed in DuckDB, a table could not be loaded for your plan, or a bundle file failed its hash check |
ValueinIntegrityError |
The point-in-time filter could not be applied to a table |
ValueinConfigError |
ValueinConfig or a tables= list is invalid |
FeedbackError |
The server rejected a report_issue() call |
from valuein_sdk import ValueinClient, ValueinError
with ValueinClient() as client:
try:
client.run_query("DELETE FROM fact")
except ValueinError as exc:
print(type(exc).__name__, exc) # ValueinValidationError and the reason
Using valuein-sdk with AI coding assistants
Paste this block into ChatGPT, Claude, Copilot or your agent's system prompt before asking for code that uses this library.
You are writing Python that uses the valuein-sdk library (PyPI: valuein-sdk).
Core API
- from valuein_sdk import ValueinClient
- Use it as a context manager:
with ValueinClient(as_of=datetime(2024, 6, 30, tzinfo=timezone.utc)) as client: ...
- as_of must be a timezone-aware datetime. It defaults to now (UTC). Point-in-time tables
(filing, fact, ratio, factor_scores, earnings_signals, stock_price, stock_price_daily
and the smart-money tables) only show rows with accepted_at <= as_of.
- client.read_table(table, columns=None, limit=None, tickers=None) -> DataFrame
- client.run_query(sql) -> DataFrame. One SELECT, WITH or EXPLAIN statement. Values go
inline as SQL literals. No read_parquet, no file or network functions.
- client.run_template(name, **params) -> DataFrame. Keyword arguments only.
client.list_templates() lists the names.
- Also: client.resolve(identifiers), client.pit_universe("YYYY-MM-DD"),
client.restatements(ticker=...), client.filing_links(ticker),
client.stock_price(ticker), client.get_schema(table), client.tables(),
client.capabilities().
- Quant layer, which needs a Pro or Institutional plan because it reads
stock_price_daily: client.factor_backtest(signal, start=, end=, freq=),
client.universe(), client.signal_panel(), client.forward_returns(),
valuein_sdk.backtest().
Rules
1. Identify companies by CIK (10 digits, zero-padded, e.g. "0000320193"). Resolve a
ticker once with client.resolve() and carry the CIK. Tickers get reused by other
companies; CIKs do not.
2. Never invent, estimate or round a financial number. Only report values the library
returned. If a query returns no rows, say so.
3. When you report a number from the fact table, cite its fact_id and accession_id. Use
client.filing_links() for the SEC URL.
4. For backtests, set as_of and use fact.numeric_value. With an explicit as_of,
value_current, restated and restatement_count are recomputed at the cutoff;
without one they are the latest export's values.
5. In SQL, write "references" with double quotes (it is a keyword). Index membership is
a JOIN on index_membership.cik; there is no is_sp500 column.
6. ratio has FY and TTM rows: always filter fiscal_period. A 10-K carries prior-year
comparatives: group by period_end, not report_date. For one quarter of a cash-flow
item use COALESCE(derived_quarterly_value, numeric_value).
7. For return math use total_return_index (or the SDK's total_return basis), never raw
close, and never add div_cash on top of it.
8. client.get(table) skips the as_of filter. Use read_table or run_query instead.
9. To run SQL you generated, create the client with
config=ValueinConfig(safe_mode=True).
10. SDK errors are ValueinError subclasses whose message states the fix. Read it before
retrying.
The SDK is data plus local compute: every query, ratio and backtest runs in your
process. Documents (DCF and comps workbooks, research briefs) come from the Valuein
Workspace or the MCP server at https://mcp.valuein.biz/mcp, which agents that call
tools instead of writing Python can use with the same token.
Examples and notebooks
Runnable examples live in the public valuein/valuein repository:
Support
- Documentation: valuein.biz/developers/python-sdk
- Questions and bugs: github.com/valuein/valuein/issues or support@valuein.biz
- A wrong number:
client.report_issue("...", category="data_quality", fact_id=..., ticker=...)sends it to the Valuein team from your code, with no token needed.
License
Apache License 2.0. See the license text.
This library and its data are for research and education. Nothing here is financial advice.
Metadata
Release files for valuein-sdk 6.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| valuein_sdk-6.1.0.tar.gz | 321.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| valuein_sdk-6.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 722.4 kB
Release files / valuein_sdk-6.1.0.tar.gz
| Download URL | valuein_sdk-6.1.0.tar.gz |
|---|---|
| Size | 321.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ab37d6a7a5d29160e1f30a94f7e60d9ac59bfd02e830dab3155ecfd19c147268
|
|
BLAKE2b-256 checksum How to use checksums |
6cd1e83cf2e9f194983314d4c12c534f45eb90a6c96947c005783b366d63cc76
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.
Transparency logRelease files / valuein_sdk-6.1.0-py3-none-any.whl
| Download URL | valuein_sdk-6.1.0-py3-none-any.whl |
|---|---|
| Size | 401.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0c1ba8c9a6e4d015d58f15942d2bf7c35d549556ce545e3ff428f802201e9fbb
|
|
BLAKE2b-256 checksum How to use checksums |
c3949e50addc367f13525e5bd05fcabc4efddde328d552cf0f455e6b9ea067ea
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.
Transparency log