Strasmore API Get an API key

Strasmore API · v1

The market, in one schema.

Run SQL directly against a full US market-data warehouse. Equities minute bars and tick data for exchange-listed stocks and ETFs from September 2003 (no OTC prints), options trades from 2014, options NBBO quotes from 2022, plus corporate actions, SEC filings, short interest, fundamentals, Treasury yields and macro series. It all lives in one schema, so you can join across datasets in a single query.

22 years
US equities, since Sep 2003
12 years
options trades, since 2014
36
tables, one schema
1
endpoint to learn

One request, one query

There is a single data endpoint. You send SQL, you get rows. There is no per-dataset endpoint to learn, no pagination cursor scheme, and no client library required.

Quickstart

Create a key in the terminal (https://ai.strasmore.com → API keys), then send a query. The key is displayed once: we store only its SHA-256 hash and cannot show it to you again.

The response is JSON. Rows come back as objects keyed by column name.

Try it — no key

Run read-only SQL against global_markets right here. This posts to https://ai.strasmore.com/api/demo/sql, the public demo endpoint: no key, no signup, 500 rows, 20s, 1 year of history, no tick trades, and 5 days of the NBBO quote tapes. It is the same gate and the same warehouse your key would query.

POST https://ai.strasmore.com/api/demo/sql
⌘/Ctrl + Enter

Authentication

Every endpoint except /v1/health takes a bearer token:

Authorization: Bearer sk_live_…

Keys resolve to an organization, and limits are applied per organization, not per key. Minting extra keys does not raise your rate limit. Revoking a key takes effect immediately.

Run a query

POST /v1/query requires key

Execute one read-only SELECT (or WITH … SELECT) against global_markets.

Body

FieldDescription
sqlrequired
string
One read-only statement. Maximum 100,000 characters.

Response

FieldDescription
columns
string[]
Column names, in result order.
rows
object[]
One object per row, keyed by column name. Not positional arrays.
row_count
integer
Rows returned, after any truncation.
truncated
boolean
True if the result hit the 20,000-row cap. The result is truncated, not errored — narrow the query, aggregate, or page with LIMIT/OFFSET.
elapsed
float
Server-side execution time, in seconds.
generated_sql
string | null
Always null today. Reserved so that adding natural-language querying later is additive rather than a breaking change.

Fetch the schema

GET /v1/schema requires key

Every table and column you can query, read from the warehouse itself at request time — so it can never drift from what your query will actually see. It reflects your tier: tables you cannot query are flagged, each table names the column its history window filters on, columns with known data defects carry a caveat, and columns whose meaning the name does not give away carry a note. plan_name beside your_tier is the pricing-page name of the slug (quotes is Pro).

Health

GET /v1/health no auth

Liveness only. Returns {"status": "ok"}. Does not check the warehouse.

SQL restrictions

Your SQL runs under a read-only database user, behind a gate that requires:

A semicolon inside a string literal is fine (WHERE name = 'Smith; Jones'), and so is a single trailing semicolon. The engine is ClickHouse, so its SQL dialect and functions apply.

Limits

LimitValue
Result rows 20,000 per query. Beyond this the result is truncated, not errored — check the truncated flag.
Query timeout 60 seconds, enforced server-side.
Request body 100,000 characters of SQL. Larger returns 422.
Free-tier daily cap 100 queries/day, in addition to the rate limit.

Rate limits

Requests per minute, applied per organization. Exceeding it returns 429. Separately, each organization can run a limited number of queries at the same time; see Concurrency.

PlanRequests / minute
Free10
Developer60
Pro600
Enterprise1200

Writing fast queries

Your account can run a limited number of queries at the same time, so a query that finishes sooner gives you more throughput. The tick-level tables are very large (the options quote tape alone holds about 7.5 trillion rows), so on them the way a query is written matters most. The advice below comes from measuring real customer queries against the warehouse.

Filter on the sort order

The tick and minute tables (cache_options_quotes, cache_stocks_quotes, stocks_trades, options_trades, options_minute_aggs) are stored in one partition per day and sorted by ticker, then time. A query that names its tickers and a time range reads only the rows it needs:

WHERE ticker IN ('O:SPY230207P00400000', 'O:SPY230207P00401000')
  AND sip_timestamp >= '2023-02-03 14:30:00'
  AND sip_timestamp <  '2023-02-03 21:00:00'

Ask for more in each query

Every query has a fixed start-up cost, so many small queries are slower than a few larger ones. Put all the contracts you need for a day in one query, up to the 20,000-row result limit. A full US session of 1-minute bars is 390 rows per contract, so about 50 contracts fit in one query. In our tests, one query for 20 contracts ran 3 times faster than 20 one-contract queries, and one query for 100 contracts ran about 1.5 times faster than five queries of 20.

Keep the per-row work simple

Work done for every row adds up over millions of rows. Prices are exact decimals and sizes are integers, so checks such as isFinite(toFloat64(bid_price)) or toUInt64OrNull(toString(bid_size)) never fail and only cost time; compare the columns directly. When you need several fields from the same row, such as the last quote in each minute, take them in one argMax over a tuple instead of one argMax per field. On a customer's 1-minute NBBO query, these two changes returned identical results about 20% faster:

WITH bid_price >= 0 AND ask_price >= bid_price AND bid_size >= 0 AND ask_size >= 0 AS valid
SELECT ticker,
       toStartOfMinute(sip_timestamp) AS minute,
       argMaxIf((sip_timestamp, bid_price, ask_price, bid_size, ask_size),
                (sip_timestamp, sequence_number), valid) AS last_quote,
       countIf(valid) AS quotes
FROM global_markets.cache_options_quotes
WHERE ticker IN ('O:SPY230207P00400000', 'O:SPY230207P00401000')
  AND sip_timestamp >= '2023-02-03 14:30:00' AND sip_timestamp < '2023-02-03 21:00:00'
GROUP BY ticker, minute
ORDER BY ticker, minute

Concurrency

Besides the per-minute rate limit, each organization can run a limited number of queries at the same moment. The number is not fixed: it rises and falls with how busy the warehouse is, and larger plans get a larger share. A query over the limit waits a few seconds for a free slot; if none opens, it returns 429 THROTTLED with a Retry-After header.

Error contract

Every error is a JSON object with detail, a stable error_code and a request_id. A query that returns zero rows is a 200, not a 404 — unless it asks only for dates before your plan's history window, which is a 402.

StatusMeaning
400 The SQL was rejected by the gate (not a single read-only SELECT, a forbidden table, a dataset your tier cannot access), or it failed to execute (syntax, unknown column). When a plan would run it (TIER_RESTRICTED_TABLE), the body names it in upgrade_plan and carries checkout_url, a link that opens checkout.
401 Missing, malformed, unknown, or revoked API key.
402 HISTORY_WINDOW_EXCEEDED — the query asks only for dates before your plan's history window, so it can return nothing on this plan. The body names the window's start, the dates you asked for, the cheapest plan that reads them (upgrade_plan) and a checkout_url that opens checkout for it.
422 Malformed request body — sql missing, or over 100,000 characters.
429 RATE_LIMITED (the per-minute limit), DAILY_QUOTA_EXCEEDED (the free-tier daily cap), or THROTTLED (more queries running at once than your share of the warehouse; see Concurrency). Every 429 carries a Retry-After header in seconds: wait that long, then send the same request again.
503 WAREHOUSE_UNREACHABLE — the problem is on our side, not in your query. Retry after the Retry-After seconds.
500 Internal error. Details are logged server-side and never returned to you.

History windows

Each plan sees a uniform depth of history across all datasets. The window is enforced server-side, on the column named by history_column in the schema catalogue.

Windows count whole calendar years, not a rolling number of days. An N-year window starts on 1 January, N years before the current year: in 2026, a 1-year window starts on 1 January 2025 and a 3-year window on 1 January 2023. The start stays fixed all year and moves forward by one year each 1 January. /v1/schema reports your exact start as history_window_start.

Older rows are withheld, and the response says so

Rows older than your window are absent from results, not an error. Every response on a windowed plan carries a history_window object: start, how far back your SQL requested_from, and clipped (true when older rows were withheld). A query that asks only for dates before the window is a 402 HISTORY_WINDOW_EXCEEDED, because no edit to the SQL can produce rows on that plan.

PlanHistoryEarliest date today
Free 1 year 1 January 2025
Developer 3 years 1 January 2023
Pro Full history Start of each dataset
Enterprise Full history Start of each dataset

Schema catalogue

36 tables in global_markets, read live from the warehouse. Query them as global_markets.<table>. Tables marked paid are unavailable on the free tier.

Equities — prices

delayed_stocks_minute_aggs 9 columns Minute OHLCV bars for US equities. The main price table. `window_start` is UTC.

history window applies to: window_start

ticker LowCardinality(String)
window_start DateTime
open Decimal(12, 4)
close Decimal(12, 4)
high Decimal(12, 4)
low Decimal(12, 4)
volume Decimal(15, 6) Leaves out the closing-auction print (condition 8) and the official open/close messages, so the 16:00 bar is NOT the close: JPM's NYSE cross on 2026-09-23 was 1,414,265 shares at 16:00:02 and its 16:00 bar reads 34,540. For auction volume read stocks_trades with has(conditions, 8) on the listing exchange. A cross can also print minutes late: XOM's NYSE close has carried an exchange timestamp of 16:01-16:05 on almost every session since June 2026.
transactions UInt32
_ingest_time DateTime
stocks_daily_aggs 11 columns Daily OHLCV bars for US equities, with `vwap` and `transactions`. The end-of-day counterpart to delayed_stocks_minute_aggs; use this for anything longer than a few sessions.

history window applies to: date

ticker LowCardinality(String) Exchange TEST ISSUES are removed from this table on every surface: the symbols the venues trade in production to test their systems (Nasdaq ZVZZT/ZXZZT, NYSE NTEST/CTEST/MTEST, Cboe ZTEST/ZBZX, IEX ZIEXT, and from 2026-09-14 the Texas Stock Exchange's ZZZTS/ZZZTA), per the Test Issue flag in Nasdaq Trader's symbol directory. They print prices no screen should rank (ZZZTS closes at $1,000,000). stocks_trades, cache_stocks_quotes and the minute bars carry the raw tape, test issues included.
date Date
open Decimal(18, 4)
close Decimal(18, 4)
high Decimal(18, 4)
low Decimal(18, 4)
volume Decimal(38, 6) Consolidated volume per the condition codes' update rules, so it is NOT the sum of size over stocks_trades (which double-counts official open/close messages and cancelled prints). If a ticker has a bar with volume here and no rows on stocks_trades for that session, that is a gap: report it. No bar at all means the symbol did not trade on an exchange that day.
vwap Decimal(18, 4)
transactions UInt32
otc UInt8
_ingest_time DateTime

Equities — tick data

stocks_trades 12 columns paid tier Tick-level equity trades (every print, with condition codes) for exchange-listed US stocks and ETFs: the consolidated CTA + UTP tape from 2003-09-10, current to the prior session. No OTC prints, so a delisted name ends on its last listed session. Paid tiers.

history window applies to: sip_timestamp

ticker String The symbol as it traded on that day, never renamed retrospectively (FB through 2022-06-08, META from 2022-06-09). Symbols are reused across issuers with nothing on the tape to tell them apart (TWTR was Tweeter until 2007-06-20 and Twitter from 2013-11-07); there is no permanent security id. Class shares use a dot (BRK.A), preferreds a lowercase p (ABKpZ).
sip_timestamp DateTime64(9) When the SIP processed the print (UTC; the partition key). Precision by era: whole seconds on most rows through 2005, milliseconds through July 2015, nanoseconds from 2015-08-03. Trails the exchange's own stamp by well under a millisecond on exchange prints; late off-exchange reports and cancel/correction records can trail by seconds to hours.
participant_timestamp DateTime64(9) The exchange's own execution stamp. Populated from 2015-07-27; before that it is the epoch placeholder (1970-01-01) on every row, so use sip_timestamp for any date earlier than that. Cancel and correction records repeat the original's value.
trf_timestamp Nullable(DateTime64(9)) When a FINRA trade-reporting facility received an off-exchange print. Populated only on off-exchange rows (exchange = 4) and only from 2015-07-27; the epoch placeholder everywhere else, never NULL.
sequence_number Int64 The SIP message sequence number; restarts every session. With ticker and session it is the key that links a cancel (10), error (11) or correction (12) record to the original print it amends.
price Decimal(12, 4)
size Decimal(15, 6)
exchange Int16 Reporting venue id: join stocks_exchanges. Off-exchange (TRF) prints all carry 4 in every year. Listing exchanges: 10 NYSE, 12 Nasdaq, 11 NYSE Arca, 1 NYSE American.
tape Int8 Which SIP feed carried the print: 1 = CTA (Tape A AND Tape B together — SPY, IWM and GLD are 1), 3 = UTP (Nasdaq-listed). It does NOT separate NYSE-listed from Arca-listed; use exchange for the listing venue.
conditions Array(Int16) Array of condition ids: join stocks_condition_codes (sip_mapping gives the CTA/UTP letter, update_rules says whether a code counts toward open/close/high/low/volume). Test with has(conditions, 8), not equality, because 9 (cross) and 41 (trade-through exempt) ride along. 15 and 16 are official open/close MESSAGES that repeat the auction print's price and size, re-sent several times a session since 2020: exclude them from executions and volume. Auction flags only exist from mid-2009 on NYSE prints (8 close, 17 open); before that the NYSE auction print is the large unflagged print at the open and after 16:00.
correction Int8 SIP correction indicator. 0 regular. 1 = original later corrected, 12 = its correction record. 8 = original later cancelled, 10 = its cancel record. 7/11 = the same for errors (last seen 2014). The 10/11/12 record carries the original's sequence_number and a later sip_timestamp (when the cancel was disseminated). Final tape: keep correction IN (0, 12).
_ingest_time DateTime
cache_stocks_quotes 15 columns 5-day preview · full history on Pro Tick-level equity NBBO quotes. Paid tiers. From 2003-09-10.

history window applies to: sip_timestamp

ticker String
sip_timestamp DateTime64(9)
participant_timestamp DateTime64(9)
trf_timestamp Nullable(DateTime64(9))
sequence_number Int64
ask_price Decimal(12, 4)
bid_price Decimal(12, 4)
ask_size Int32
bid_size Int32
ask_exchange Int16
bid_exchange Int16
tape Int8
conditions Array(Int16)
indicators Array(Int16)
_ingest_time DateTime

Options

options_greeks 18 columns paid tier Daily Black-Scholes IV + greeks per contract (EOD close, delta/gamma/vega/theta/rho). One row per contract per session, 2014 onward, refreshed nightly. Paid tiers.

history window applies to: date

date Date
ticker String
underlying_symbol String
option_type String
strike_price Float64
expiration_date Nullable(Date)
volume UInt64
option_close Float64
underlying_close Float64
risk_free_rate Nullable(Float64)
days_to_expiry Nullable(Float64)
implied_volatility Nullable(Float64) Solved from the EOD option close by bisection. Screen implied_volatility > 0.02 to drop degenerate fits.
iv_converged Nullable(UInt8) Filter iv_converged = 1: rows where the IV solve did not converge carry NULL greeks (deep ITM/OTM or stale closes).
delta Nullable(Float64)
gamma Nullable(Float64)
vega Nullable(Float64)
theta Nullable(Float64)
rho Nullable(Float64)
options_trades 13 columns paid tier Tick-level options trades (OPRA). Paid tiers. From 2014.

history window applies to: sip_timestamp

ticker LowCardinality(String)
sip_timestamp DateTime64(9)
participant_timestamp DateTime64(9)
price Decimal(10, 4)
size UInt32
exchange UInt8
conditions Array(UInt16)
correction UInt8
underlying_symbol LowCardinality(String)
expiration_date Date Unreliable. Parse the expiry from the option ticker instead.
strike_price Decimal(18, 3)
option_type LowCardinality(String)
_ingest_time DateTime
cache_options_quotes 10 columns 5-day preview · full history on Pro Tick-level options NBBO quotes. Paid tiers. From 2022. The largest table by far.

history window applies to: sip_timestamp

ticker LowCardinality(String)
sip_timestamp DateTime64(9)
sequence_number Int64
ask_price Decimal(10, 2)
bid_price Decimal(10, 2)
ask_size Int32
bid_size Int32
ask_exchange Int16
bid_exchange Int16
_ingest_time DateTime
options_minute_aggs 9 columns Minute OHLCV bars per options contract.

history window applies to: window_start

ticker LowCardinality(String)
window_start DateTime
open Decimal(10, 4)
close Decimal(10, 4)
high Decimal(10, 4)
low Decimal(10, 4)
volume UInt64
transactions UInt32
_ingest_time DateTime

Corporate actions

stocks_dividends 13 columns Declared dividends: ex-date, record date, pay date, cash amount.

history window applies to: ex_dividend_date

ex_dividend_date Date
ticker String
id String
cash_amount Nullable(Float64)
currency String
declaration_date Nullable(Date)
pay_date Nullable(Date)
record_date Nullable(Date)
frequency Nullable(Int32)
distribution_type String
split_adjusted_cash_amount Nullable(Float64)
historical_adjustment_factor Nullable(Float64)
_ingest_time DateTime
stocks_splits 8 columns Stock splits (forward and reverse) with execution date and ratio.

history window applies to: execution_date

execution_date Date
ticker String
id String
split_from Nullable(Float64)
split_to Nullable(Float64)
adjustment_type String
historical_adjustment_factor Nullable(Float64)
_ingest_time DateTime
stocks_ipos 23 columns IPO / new listing records: issue price, shares offered, listing date.

history window applies to: listing_date

listing_date Date
ticker String
issuer_name String
ipo_status String
announced_date Nullable(Date)
issue_start_date Nullable(Date)
issue_end_date Nullable(Date)
final_issue_price Nullable(Float64)
lowest_offer_price Nullable(Float64)
highest_offer_price Nullable(Float64)
total_offer_size Nullable(Float64)
min_shares_offered Nullable(Float64)
max_shares_offered Nullable(Float64)
shares_outstanding Nullable(Float64)
lot_size Nullable(Float64)
currency_code String
security_type String
security_description String
primary_exchange String
isin String
us_code String
last_updated Nullable(Date)
_ingest_time DateTime

Short data

stocks_short_interest 6 columns Exchange-reported short interest, by settlement date (twice monthly).

history window applies to: settlement_date

settlement_date Date
ticker String
short_interest Nullable(Float64)
avg_daily_volume Nullable(Float64)
days_to_cover Nullable(Float64)
_ingest_time DateTime
stocks_short_volume 16 columns Daily FINRA short volume (can carry duplicate rows: GROUP BY + max()).

history window applies to: date

date Date This table can contain duplicate rows for a ticker/date. Dedupe with GROUP BY + max().
ticker String
short_volume Nullable(Float64)
short_volume_ratio Nullable(Float64)
total_volume Nullable(Float64)
exempt_volume Nullable(Float64)
non_exempt_volume Nullable(Float64)
adf_short_volume Nullable(Float64)
adf_short_volume_exempt Nullable(Float64)
nasdaq_carteret_short_volume Nullable(Float64)
nasdaq_carteret_short_volume_exempt Nullable(Float64)
nasdaq_chicago_short_volume Nullable(Float64)
nasdaq_chicago_short_volume_exempt Nullable(Float64)
nyse_short_volume Nullable(Float64)
nyse_short_volume_exempt Nullable(Float64)
_ingest_time DateTime

Fundamentals

stocks_income_statements 35 columns Quarterly/annual income statements.

history window applies to: filing_date

period_end Date
filing_date Date UNRELIABLE. Vendor defect: ~89% of quarterly rows carry a filing_date more than 200 days after period_end (older fiscal years are stamped with recent years' dates). Use period_end as the time key.
cik String
tickers Array(String)
fiscal_year Nullable(Int32)
fiscal_quarter Nullable(Int8)
timeframe String
revenue Nullable(Float64)
cost_of_revenue Nullable(Float64)
gross_profit Nullable(Float64)
operating_income Nullable(Float64)
net_income_loss_attributable_common_shareholders Nullable(Float64)
consolidated_net_income_loss Nullable(Float64)
basic_earnings_per_share Nullable(Float64)
basic_shares_outstanding Nullable(Float64)
diluted_earnings_per_share Nullable(Float64)
diluted_shares_outstanding Nullable(Float64)
ebitda Nullable(Float64)
selling_general_administrative Nullable(Float64)
research_development Nullable(Float64)
total_operating_expenses Nullable(Float64)
income_before_income_taxes Nullable(Float64)
income_taxes Nullable(Float64)
interest_expense Nullable(Float64)
interest_income Nullable(Float64)
depreciation_depletion_amortization Nullable(Float64)
discontinued_operations Nullable(Float64)
equity_in_affiliates Nullable(Float64)
extraordinary_items Nullable(Float64)
noncontrolling_interest Nullable(Float64)
other_income_expense Nullable(Float64)
other_operating_expenses Nullable(Float64)
preferred_stock_dividends_declared Nullable(Float64)
total_other_income_expense Nullable(Float64)
_ingest_time DateTime
stocks_balance_sheets 39 columns Quarterly/annual balance sheets.

history window applies to: filing_date

period_end Date
filing_date Date PARTLY UNRELIABLE (~43% of rows filed >200d after period_end). Prefer period_end.
cik String
tickers Array(String)
fiscal_year Nullable(Int32)
fiscal_quarter Nullable(Int8)
timeframe String
total_assets Nullable(Float64)
total_current_assets Nullable(Float64)
total_liabilities Nullable(Float64)
total_current_liabilities Nullable(Float64)
total_equity Nullable(Float64)
cash_and_equivalents Nullable(Float64)
accounts_payable Nullable(Float64)
accrued_and_other_current_liabilities Nullable(Float64)
accumulated_other_comprehensive_income Nullable(Float64)
additional_paid_in_capital Nullable(Float64)
commitments_and_contingencies Nullable(Float64)
common_stock Nullable(Float64)
debt_current Nullable(Float64)
deferred_revenue_current Nullable(Float64)
goodwill Nullable(Float64)
intangible_assets_net Nullable(Float64)
inventories Nullable(Float64)
long_term_debt_and_capital_lease_obligations Nullable(Float64)
noncontrolling_interest Nullable(Float64)
other_assets Nullable(Float64)
other_current_assets Nullable(Float64)
other_equity Nullable(Float64)
other_noncurrent_liabilities Nullable(Float64)
preferred_stock Nullable(Float64)
property_plant_equipment_net Nullable(Float64)
receivables Nullable(Float64)
retained_earnings_deficit Nullable(Float64)
short_term_investments Nullable(Float64)
total_equity_attributable_to_parent Nullable(Float64)
total_liabilities_and_equity Nullable(Float64)
treasury_stock Nullable(Float64)
_ingest_time DateTime
stocks_cash_flow_statements 33 columns Quarterly/annual cash-flow statements.

history window applies to: filing_date

period_end Date
filing_date Date UNRELIABLE (same vendor defect as stocks_income_statements). Use period_end.
cik String
tickers Array(String)
fiscal_year Nullable(Int32)
fiscal_quarter Nullable(Int8)
timeframe String
net_income Nullable(Float64)
net_cash_from_operating_activities Nullable(Float64)
net_cash_from_investing_activities Nullable(Float64)
net_cash_from_financing_activities Nullable(Float64)
change_in_cash_and_equivalents Nullable(Float64)
cash_from_operating_activities_continuing_operations Nullable(Float64)
change_in_other_operating_assets_and_liabilities_net Nullable(Float64)
depreciation_depletion_and_amortization Nullable(Float64)
dividends Nullable(Float64)
effect_of_currency_exchange_rate Nullable(Float64)
income_loss_from_discontinued_operations Nullable(Float64)
long_term_debt_issuances_repayments Nullable(Float64)
net_cash_from_financing_activities_continuing_operations Nullable(Float64)
net_cash_from_financing_activities_discontinued_operations Nullable(Float64)
net_cash_from_investing_activities_continuing_operations Nullable(Float64)
net_cash_from_investing_activities_discontinued_operations Nullable(Float64)
net_cash_from_operating_activities_discontinued_operations Nullable(Float64)
noncontrolling_interests Nullable(Float64)
other_cash_adjustments Nullable(Float64)
other_financing_activities Nullable(Float64)
other_investing_activities Nullable(Float64)
other_operating_activities Nullable(Float64)
purchase_of_property_plant_and_equipment Nullable(Float64)
sale_of_property_plant_and_equipment Nullable(Float64)
short_term_debt_issuances_repayments Nullable(Float64)
_ingest_time DateTime
stocks_ratios 24 columns Valuation and financial ratios (P/E, P/B, EV/EBITDA, yields, ROE, market cap) — a CURRENT SNAPSHOT: one row per ticker, replaced whole at each load. The vendor publishes the latest session only, so there is no history here; derive a past ratio from the statements and stocks_daily_aggs.

history window applies to: date

date Date The session this ticker's ratios were computed for. The table is a snapshot, one row per ticker: dates differ only because a ticker without a fresh price keeps an older row, and there is no year-ago row to compare against.
ticker String
cik String
price Nullable(Float64)
market_cap Nullable(Float64)
enterprise_value Nullable(Float64)
average_volume Nullable(Float64)
earnings_per_share Nullable(Float64)
price_to_earnings Nullable(Float64)
price_to_book Nullable(Float64)
price_to_sales Nullable(Float64)
price_to_cash_flow Nullable(Float64)
price_to_free_cash_flow Nullable(Float64)
ev_to_ebitda Nullable(Float64)
ev_to_sales Nullable(Float64)
dividend_yield Nullable(Float64)
return_on_assets Nullable(Float64)
return_on_equity Nullable(Float64)
debt_to_equity Nullable(Float64)
current Nullable(Float64)
quick Nullable(Float64)
cash Nullable(Float64)
free_cash_flow Nullable(Float64)
_ingest_time DateTime

Ownership & insiders

stocks_13f_filings 21 columns Institutional holdings from 13F-HR filings — one row per position per manager per quarter (`filer_cik`, `cusip`, `market_value`, `shares_or_principal_amount`, voting authority). Back to 2000. Join to a quarter with `period`, to the filing with `filing_date`.
accession_number String
cusip Nullable(String)
file_number Nullable(String)
filer_cik String
filing_date Date
filing_url Nullable(String)
film_number Nullable(String)
form_type Nullable(String)
investment_discretion Nullable(String)
issuer_name Nullable(String)
market_value Nullable(Int64)
other_managers Array(String)
period Nullable(Date) 334 rows carry an out-of-range period (as filed — they range to 1987 and to 2149). Tiny against 160m rows, but enough to poison the obvious idiom: max(period) returns 2149-06-06 and a 'latest quarter' query then matches one row. Bound it — max(period) WHERE period <= today().
put_call Nullable(String)
shares_or_principal_amount Nullable(Int64)
shares_or_principal_type Nullable(String)
title_of_class Nullable(String)
voting_authority_none Nullable(Int64)
voting_authority_shared Nullable(Int64)
voting_authority_sole Nullable(Int64)
_ingest_time DateTime
stocks_form4 41 columns Insider transactions (SEC Form 4): open-market buys and sells, grants and exercises by officers, directors and 10% owners. `transaction_code` is the action, `transaction_shares`/`transaction_price_per_share` the size. `tickers` is an ARRAY — filter with has(tickers, 'AAPL'). Back to 2003.
accession_number String
aff_10b5_one Nullable(UInt8)
date_of_original_submission Nullable(Date)
deemed_execution_date Nullable(Date)
direct_or_indirect Nullable(String)
equity_swap_involved Nullable(UInt8)
exercise_date Nullable(Date)
exercise_price Nullable(Float64)
expiration_date Nullable(Date)
filing_date Date
filing_url Nullable(String)
footnotes Nullable(String)
form_type Nullable(String)
is_director Nullable(UInt8)
is_officer Nullable(UInt8)
is_other Nullable(UInt8)
is_ten_percent_owner Nullable(UInt8)
issuer_cik String
issuer_name Nullable(String)
nature_of_ownership Nullable(String)
not_subject_to_section_16 Nullable(UInt8)
officer_title Nullable(String)
owner_cik Nullable(String)
owner_name Nullable(String)
period_of_report Nullable(Date)
record_type Nullable(String)
remarks Nullable(String)
security_title Nullable(String)
security_type Nullable(String)
shares_owned_following_transaction Nullable(Float64)
tickers Array(String)
transaction_acquired_disposed Nullable(String)
transaction_code Nullable(String)
transaction_date Nullable(Date)
transaction_price_per_share Nullable(Float64) Carries a small tail of mis-parsed values as filed — ~0.3% of open-market purchases price above $100,000/share, and in some rows the SHARE COUNT is repeated into this field. Harmless to ignore until you ORDER BY value, which puts them first. Bound it (e.g. BETWEEN 1 AND 10000) for any ranking. transaction_value is derived from this column and inherits the defect.
transaction_shares Nullable(Float64)
transaction_timeliness Nullable(String)
transaction_value Nullable(Float64)
underlying_security_shares Nullable(Float64)
underlying_security_title Nullable(String)
_ingest_time DateTime
stocks_form3 30 columns Initial statements of beneficial ownership (SEC Form 3) — filed when someone first becomes an insider. The starting position that Form 4 transactions then move. `tickers` is an ARRAY.
accession_number String
aff_10b5_one Nullable(UInt8)
date_of_original_submission Nullable(Date)
direct_or_indirect Nullable(String)
exercise_date Nullable(Date)
exercise_price Nullable(Float64)
filing_date Date
filing_url Nullable(String)
footnotes Nullable(String)
form_type Nullable(String)
is_director Nullable(UInt8)
is_officer Nullable(UInt8)
is_other Nullable(UInt8)
is_ten_percent_owner Nullable(UInt8)
issuer_cik String
issuer_name Nullable(String)
nature_of_ownership Nullable(String)
not_subject_to_section_16 Nullable(UInt8)
officer_title Nullable(String)
owner_cik Nullable(String)
owner_name Nullable(String)
period_of_report Nullable(Date)
remarks Nullable(String)
security_title Nullable(String)
security_type Nullable(String)
shares_owned Nullable(Float64)
tickers Array(String)
underlying_security_shares Nullable(Float64)
underlying_security_title Nullable(String)
_ingest_time DateTime

SEC filings

stocks_sec_edgar_index 8 columns The EDGAR filing index: every filing, its form type and filing date.

history window applies to: filing_date

cik String
ticker String
issuer_name String
form_type String
filing_date Date
accession_number String
filing_url String
_ingest_time DateTime
stocks_10k_sections 8 columns Parsed sections of 10-K filings.

history window applies to: filing_date

cik String
ticker String
filing_date Date
period_end Date
filing_url String
section String
text String
_ingest_time DateTime
stocks_8k_disclosures 10 columns 8-K material-event filings, categorised (`primary_category` … `tertiary_category`) with the supporting text. `tickers` is an ARRAY. See stocks_8k_text for the full filing body.
accession_number String
cik String
filing_date Date
filing_url Nullable(String)
primary_category Nullable(String)
secondary_category Nullable(String)
tertiary_category Nullable(String)
supporting_text Nullable(String)
tickers Array(String)
_ingest_time DateTime
stocks_8k_text 8 columns 8-K filing text.

history window applies to: filing_date

cik String
ticker String
form_type String
filing_date Date
accession_number String
filing_url String
items_text String
_ingest_time DateTime
stocks_13f_text 7 columns Raw 13F filing text. NOT YET POPULATED — the table exists and is empty; use stocks_13f_filings for the parsed positions.
accession_number String
filer_cik String
filing_date Date
form_type Nullable(String)
filing_url String
filing_text String
_ingest_time DateTime
stocks_risk_factors 8 columns Parsed risk-factor sections.

history window applies to: filing_date

cik String
ticker String
filing_date Date
primary_category String
secondary_category String
tertiary_category String
supporting_text String
_ingest_time DateTime
stocks_risk_categories 6 columns Reference: risk-factor category labels.
taxonomy String
primary_category String
secondary_category String
tertiary_category String
description String
_ingest_time DateTime

News

stocks_news 13 columns News article metadata (headline, publisher, tickers). Not full article text.

history window applies to: published_utc

id String
published_utc DateTime
title String
author String
article_url String
amp_url String
image_url String
description String
tickers Array(String)
keywords Array(String)
insights Array(String)
publisher String
_ingest_time DateTime

Macro & rates

treasury_yields 13 columns US Treasury yield curve by maturity, daily.

history window applies to: date

date Date
yield_1_month Nullable(Float32)
yield_3_month Nullable(Float32)
yield_6_month Nullable(Float32)
yield_1_year Nullable(Float32)
yield_2_year Nullable(Float32)
yield_3_year Nullable(Float32)
yield_5_year Nullable(Float32)
yield_7_year Nullable(Float32)
yield_10_year Nullable(Float32)
yield_20_year Nullable(Float32)
yield_30_year Nullable(Float32)
_ingest_time DateTime
inflation 8 columns CPI / PCE series.

history window applies to: date

date Date
cpi Nullable(Float32)
cpi_core Nullable(Float32)
cpi_year_over_year Nullable(Float32)
pce Nullable(Float32)
pce_core Nullable(Float32)
pce_spending Nullable(Float64)
_ingest_time DateTime
inflation_expectations 9 columns Inflation expectation series.

history window applies to: date

date Date
forward_years_5_to_10 Nullable(Float32)
market_5_year Nullable(Float32)
market_10_year Nullable(Float32)
model_1_year Nullable(Float32)
model_5_year Nullable(Float32)
model_10_year Nullable(Float32)
model_30_year Nullable(Float32)
_ingest_time DateTime
labor_market 6 columns Labor-market series.

history window applies to: date

date Date
avg_hourly_earnings Nullable(Float32)
job_openings Nullable(Float32)
labor_force_participation_rate Nullable(Float32)
unemployment_rate Nullable(Float32)
_ingest_time DateTime

Reference

stocks_market_holidays 7 columns Exchange calendar: holidays and early closes.
date Date
exchange String
name String
status String
open Nullable(DateTime)
close Nullable(DateTime)
_ingest_time DateTime
stocks_market_status 8 columns Reference: market status codes.
afterHours Nullable(Bool)
currencies String
earlyHours Nullable(Bool)
exchanges String
indicesGroups String
market String
serverTime DateTime
_ingest_time DateTime
stocks_exchanges 11 columns Reference: exchange codes and names.
id Int64
type String
asset_class String
locale String
name String
acronym String
mic String
operating_mic String
participant_id String
url String
_ingest_time DateTime
stocks_condition_codes 12 columns Reference: trade/quote condition codes (needed to read the tick tables).
id Int64
name String
abbreviation String
type String
description String
asset_class String
data_types Array(String)
legacy Nullable(Bool)
exchange Nullable(Int64)
sip_mapping String JSON: the letter each SIP (CTA, UTP, FINRA_TDDS) uses for this numeric code.
update_rules String JSON: for each of consolidated and market_center, whether prints with this code update the high/low, the open/close and the volume. The consolidated rule is what daily bars follow.
_ingest_time DateTime

Trade tape field guide

What the columns of stocks_trades mean, and the four things a point-in-time simulator has to get right. Every statement here was measured on the warehouse itself (mid-March sessions of every year 2003–2026, plus two full sessions), not copied from a vendor page. The same facts ride on each column as a note in GET /v1/schema.

Coverage

The consolidated SIP tape (CTA and UTP) for exchange-listed US stocks and ETFs, from 2003-09-10, every trading session since, current to the prior session with a one to two day ingest lag. Delisted names are present through their last listed session. OTC and pink-sheet prints are not included, so a post-delisting symbol such as SIVBQ returns nothing. To read a zero-row result: if stocks_daily_aggs has a bar with volume for that ticker and session and the tape has no rows, that is a gap — tell us. No bar either means the symbol did not trade on an exchange that day.

Timestamps

Periodparticipant_timestamptrf_timestampsip_timestamp precision
2003-09-10 → 2005epoch placeholder on every rowepoch placeholderwhole seconds on most rows
2006 → 2015-07-24epoch placeholder on every rowepoch placeholdermilliseconds
2015-07-27 →populated (the exchange's own stamp)populated on off-exchange prints onlynanoseconds from 2015-08-03

The SIP stamp is dissemination time: it trails the exchange stamp by a fraction of a millisecond on exchange prints and by up to seconds on late off-exchange reports. The execution time to use is therefore participant_timestamp from 2015-07-27 and sip_timestamp before — one expression covers both:

if(toUnixTimestamp64Nano(participant_timestamp) = 0, sip_timestamp, participant_timestamp) AS executed_at

Venue and tape

exchange is the reporting venue (join stocks_exchanges): 10 NYSE, 12 Nasdaq, 11 NYSE Arca, 1 NYSE American; every off-exchange (TRF) print carries 4, in every year. tape is the SIP feed that carried the print — 1 for CTA, 3 for UTP — and CTA covers both Tape A and Tape B, so SPY, IWM and GLD are stored as 1. Use exchange, not tape, to find the listing venue.

Opening and closing auctions

The condition codes are one set for the whole history (stocks_condition_codes carries the CTA/UTP letter for each and an update_rules column saying whether a code counts toward open, close, high, low and volume). What varies by year is whether the SIP sent the flag.

CodeMeaningNYSE-listed (exchange 10)Nasdaq-listed (exchange 12)
17opening auction printfrom August 2009; [17, 41] from 2020[17, 9] from at least 2008; 41 added 2020
8closing auction printfrom June 2009; [8, 41] from 2020[8, 9] from at least 2008; 41 added 2020
16official open messagefrom 2021from 2005
15official close messagefrom 2017, re-sent 3–4× a session since 2020from 2003

Two rules follow. Codes 15 and 16 are messages, not executions — they repeat the auction print's price and size — so exclude them from executions and from volume. And before mid-2009 the NYSE auction prints carry no flag at all: on exchange 10 they are the first print at or after 09:30 and the largest print after 16:00, both unflagged. Through 2020 the NYSE closing print was regularly reported one to two and a half minutes after the bell, and from 2015-07-27 the exchange's own stamp confirms that is when the auction completed, not a dissemination delay.

-- The closing auction print, NYSE-listed name, one session (the 9 and 41 flags ride along, so test with has()).
SELECT toString(toDateTime64(sip_timestamp, 3, 'America/New_York'))         AS printed_et,
       toString(toDateTime64(participant_timestamp, 3, 'America/New_York')) AS exchange_stamp_et,
       price, size, exchange, conditions
FROM global_markets.stocks_trades
WHERE ticker = 'IBM' AND exchange = 10
  AND sip_timestamp >= toDateTime('2023-03-15 15:55:00', 'America/New_York')
  AND sip_timestamp <  toDateTime('2023-03-15 16:15:00', 'America/New_York')
  AND has(conditions, 8) AND correction = 0
ORDER BY sip_timestamp

Corrections and cancellations

correctionMeaningIn the final tape?
0regular print, never amendedyes
1 → 12original later corrected → the correction record (the corrected fields)keep the 12
8 → 10original later cancelled → the cancel recorddrop both
7 → 11original later marked erroneous → the error record (last seen 2014)drop both

A 10, 11 or 12 record carries the original print's sequence_number, exchange and participant stamp, with a later sip_timestamp: the moment the amendment was disseminated. Sequence numbers restart each session, so the key is (ticker, session, sequence_number). Amendments are rare — roughly 0.001% to 0.03% of prints on a session — and the counts pair exactly. For a point-in-time replay keep the originals and apply the 10 or 12 at its own SIP time.

-- The final tape for one symbol-session: drop amended and cancelled originals, keep corrections, drop the open/close messages.
SELECT sip_timestamp, participant_timestamp, sequence_number, price, size, exchange, conditions, correction
FROM global_markets.stocks_trades
WHERE ticker = 'AAPL'
  AND sip_timestamp >= toDateTime('2023-03-15 04:00:00', 'America/New_York')
  AND sip_timestamp <  toDateTime('2023-03-15 20:00:00', 'America/New_York')
  AND correction IN (0, 12)
  AND NOT hasAny(conditions, [15, 16])
ORDER BY sip_timestamp, sequence_number

Symbol identity

ticker is the symbol as it traded on that day, never renamed after the fact: FB prints through 2022-06-08 and META from 2022-06-09. Symbols are reused across issuers with nothing on the tape to tell them apart — TWTR was Tweeter Home Entertainment until 2007-06-20 and Twitter from 2013-11-07; GM and DELL both have gaps between two different companies. There is no permanent security identifier on the tape (a CIK exists only on the SEC-derived tables). For a multi-year study, build a (ticker, first date, last date, security id) map from an external master and join on ticker and session.

Data caveats

Known defects in the underlying data. We publish them rather than let you discover them: a silently wrong number is worse than a missing one. They are also attached to the affected columns in GET /v1/schema.

options_greeks.iv_converged

Filter iv_converged = 1: rows where the IV solve did not converge carry NULL greeks (deep ITM/OTM or stale closes).

options_greeks.implied_volatility

Solved from the EOD option close by bisection. Screen implied_volatility > 0.02 to drop degenerate fits.

options_trades.expiration_date

Unreliable. Parse the expiry from the option ticker instead.

stocks_13f_filings.period

334 rows carry an out-of-range period (as filed — they range to 1987 and to 2149). Tiny against 160m rows, but enough to poison the obvious idiom: max(period) returns 2149-06-06 and a 'latest quarter' query then matches one row. Bound it — max(period) WHERE period <= today().

stocks_balance_sheets.filing_date

PARTLY UNRELIABLE (~43% of rows filed >200d after period_end). Prefer period_end.

stocks_cash_flow_statements.filing_date

UNRELIABLE (same vendor defect as stocks_income_statements). Use period_end.

stocks_form4.transaction_price_per_share

Carries a small tail of mis-parsed values as filed — ~0.3% of open-market purchases price above $100,000/share, and in some rows the SHARE COUNT is repeated into this field. Harmless to ignore until you ORDER BY value, which puts them first. Bound it (e.g. BETWEEN 1 AND 10000) for any ranking. transaction_value is derived from this column and inherits the defect.

stocks_income_statements.filing_date

UNRELIABLE. Vendor defect: ~89% of quarterly rows carry a filing_date more than 200 days after period_end (older fiscal years are stamped with recent years' dates). Use period_end as the time key.

stocks_short_volume.date

This table can contain duplicate rows for a ticker/date. Dedupe with GROUP BY + max().

Data usage

Can I keep the data locally, and what happens if I cancel?

We do not issue individual written confirmations regarding market-data rights, storage, retention, or the specific requirements of exchanges, SIPs, and other third-party providers. What a Strasmore subscription permits is governed by our Terms of Service, with Section 4.4 addressing third-party data specifically. Review them against your intended use; if they do not provide the certainty your project requires, we recommend consulting market-data counsel. Read the Terms.