What Does Historical Tick Data Cost?
Historical tick data is priced on four axes: venue, schema, volume delivered, and license type. Here is how each axis works, with real record counts.
What historical tick data costs is really three separate bills, and most of the prices people repeat to each other leave out which bill is being quoted. The first is the license for the data itself, held by the exchange or by the consolidated tape. The second is the vendor's charge for extracting a slice of that history and delivering it to you. The third is what you pay to keep the files after they land, which we work through in how to store market data pcaps.
Tick data means the individual messages: every trade print and every quote update, each carrying its own timestamp, venue code and sequence number. A minute bar is a summary of those messages. The distance between the two is the entire cost story.
What are you actually paying for?
The license is the part newcomers underestimate. Exchanges and the tape operators own their historical record and grant you a defined use of it. The narrowest grant is internal use: your team may study the files, and nothing built from them leaves the building in a form an outsider can read. A display grant lets you show values to your own users. A redistribution grant lets you hand the data, or something close enough to it, to third parties. Same bytes, three prices, and the multiple between the narrowest and the widest is large. The entitlement categories that govern live feeds have a historical cousin here, and we cover the live side in professional vs non-professional market data.
The delivery charge is the vendor's own. Someone holds decades of messages, indexes them, pulls your slice, normalizes the schema and ships it. That work gets billed per request, per symbol-day, per gigabyte out, or as a flat annual seat. Vendors differ wildly on which, which is why two proposals for the same dataset can look nothing alike.
The third bill is yours, and it is the one with no negotiation in it. Ticks land as files you now own and must keep.
How is historical tick data priced?
Read any proposal by finding these four axes in it.
- Per venue. US equities print on more than a dozen exchanges plus off-exchange reporting facilities. One exchange's own historical feed contains that exchange's activity and nothing else. The consolidated tape contains all of it, at a different price.
- Per schema. Trades, top-of-book quotes, and full order book depth are three products of very different sizes.
- Per volume delivered. Symbol-days, message counts, or compressed bytes. This axis moves with the market, not with your budget.
- Per license grant. Internal, display, or redistribution, as above.
Why quote history costs more than trade history
Take one ordinary Wednesday session, August 19, 2026, and count what five household names put on the tape between 4:00 a.m. and 4:00 a.m. ET the next day. The trade file and the quote file for the same stock on the same day are not remotely the same size.
| symbol | trade_millions | quote_millions | quotes_per_trade |
|---|---|---|---|
| NVDA | 2.05 | 2.11 | 1 |
| AAPL | 0.9 | 1.2 | 1.3 |
| SPY | 0.52 | 3.05 | 5.9 |
| MSFT | 0.41 | 0.31 | 0.8 |
| KO | 0.29 | 0.47 | 1.6 |
The exact SQL behind every number
SELECT
t.symbol AS symbol,
round(t.trades / 1e6, 2) AS trade_millions,
round(q.quotes / 1e6, 2) AS quote_millions,
round(q.quotes / t.trades, 1) AS quotes_per_trade
FROM
(
SELECT
ticker AS symbol,
count() AS trades
FROM global_markets.stocks_trades
WHERE ticker IN ('SPY', 'AAPL', 'NVDA', 'MSFT', 'KO')
AND sip_timestamp >= toDateTime('2026-08-19 08:00:00')
AND sip_timestamp < toDateTime('2026-08-20 08:00:00')
GROUP BY ticker
) AS t
INNER JOIN
(
SELECT
ticker AS symbol,
count() AS quotes
FROM global_markets.cache_stocks_quotes
WHERE ticker IN ('SPY', 'AAPL', 'NVDA', 'MSFT', 'KO')
AND sip_timestamp >= toDateTime('2026-08-19 08:00:00')
AND sip_timestamp < toDateTime('2026-08-20 08:00:00')
GROUP BY ticker
) AS q ON q.symbol = t.symbol
ORDER BY trade_millions DESCNVDA sat at the top with 2.05 million trade messages against 2.11 million quote updates, a ratio of 1 quotes for every print. KO, the lightest trade tape of the group, still carried 1.6 quotes per trade. A vendor billing on messages delivered is looking at that quote column, not the trade column, and full order book depth sits above both: every price level and every revision, not only the best bid and offer.
What one venue's history leaves out
The per-venue axis is easy to miss until the data arrives. A single stock's prints scatter across every exchange it trades on plus the off-exchange reporting facilities, and each venue sells only its own record. Buying one feed's history buys one column of this chart.
| venue | trade_thousands | share_pct |
|---|---|---|
| FINRA Alternative Display Facility | 237.6 | 45.8 |
| NYSE Arca, Inc. | 78.8 | 15.2 |
| Nasdaq | 77.8 | 15 |
| Cboe BZX | 38.4 | 7.4 |
| Cboe EDGX | 21.9 | 4.2 |
| Investors Exchange | 19 | 3.7 |
| New York Stock Exchange | 17.5 | 3.4 |
| Members Exchange | 10.8 | 2.1 |
| Cboe EDGA | 4.6 | 0.9 |
| Cboe BYX | 4 | 0.8 |
| Nasdaq Philadelphia Exchange LLC | 2.5 | 0.5 |
| MIAX Pearl | 1.9 | 0.4 |
The exact SQL behind every number
SELECT
if(ex.name = '', concat('Venue ', toString(d.exchange)), ex.name) AS venue,
round(d.trades / 1000, 1) AS trade_thousands,
round(100 * d.trades / sum(d.trades) OVER (), 1) AS share_pct
FROM
(
SELECT
toInt32(exchange) AS exchange,
count() AS trades
FROM global_markets.stocks_trades
WHERE ticker = 'SPY'
AND sip_timestamp >= toDateTime('2026-08-19 08:00:00')
AND sip_timestamp < toDateTime('2026-08-20 08:00:00')
GROUP BY exchange
) AS d
LEFT JOIN
(
SELECT
toInt32(id) AS id,
any(name) AS name
FROM global_markets.stocks_exchanges
WHERE asset_class = 'stocks'
GROUP BY id
) AS ex ON ex.id = d.exchange
ORDER BY d.trades DESC
LIMIT 12That session's SPY prints spread over 12 reporting venues in the list above. The largest, FINRA Alternative Display Facility, took 45.8 percent of them and 237.6 thousand messages. Every other venue is a separate historical product from a separate counterparty with a separate contract. The consolidated view is one purchase instead of a dozen, with its own fee schedule; the structural difference is the same one described in SIP vs direct exchange feeds.
Volume delivered is a moving target
When the bill is per message or per gigabyte, the number you are quoted in a proposal is an estimate of market activity, and activity moves. Here is the daily trade-record count for two stocks across the pinned August 2026 window, taken from the per-minute transaction counts.
| date | spy_trade_millions | aapl_trade_millions |
|---|---|---|
| 2026-08-03 | 0.81 | 1.39 |
| 2026-08-04 | 0.83 | 1.1 |
| 2026-08-05 | 0.7 | 0.96 |
| 2026-08-06 | 0.61 | 0.83 |
| 2026-08-07 | 0.58 | 0.72 |
| 2026-08-10 | 0.56 | 0.92 |
| 2026-08-11 | 0.52 | 0.76 |
| 2026-08-12 | 0.5 | 0.88 |
| 2026-08-13 | 0.5 | 0.78 |
| 2026-08-14 | 0.47 | 0.62 |
| 2026-08-17 | 0.52 | 0.77 |
| 2026-08-18 | 0.56 | 0.91 |
| 2026-08-19 | 0.52 | 0.9 |
| 2026-08-20 | 0.6 | 0.71 |
| 2026-08-21 | 0.49 | 0.67 |
| 2026-08-24 | 0.49 | 0.83 |
| 2026-08-25 | 0.46 | 0.6 |
| 2026-08-26 | 0.45 | 0.66 |
| 2026-08-27 | 0.5 | 0.72 |
| 2026-08-28 | 0.55 | 0.76 |
The exact SQL behind every number
SELECT
toDate(toTimeZone(window_start, 'America/New_York')) AS date,
round(sumIf(transactions, ticker = 'SPY') / 1e6, 2) AS spy_trade_millions,
round(sumIf(transactions, ticker = 'AAPL') / 1e6, 2) AS aapl_trade_millions
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'AAPL')
AND window_start >= toDateTime('2026-08-03 04:00:00')
AND window_start < toDateTime('2026-09-01 04:00:00')
GROUP BY date
HAVING spy_trade_millions > 0
ORDER BY dateOver 21 sessions, SPY opened the window at 0.81 million trade records and finished it at 0.53 million, with AAPL alongside at 1.39 million on the first session. The line between those points is the part a flat per-symbol-day quote absorbs and a per-message quote does not.
The lumpiness repeats inside the day, which matters when a vendor caps a single extract.
| et_hour | spy_trade_thousands |
|---|---|
| 04:00 | 2.4 |
| 05:00 | 0.5 |
| 06:00 | 0.4 |
| 07:00 | 1.2 |
| 08:00 | 11.8 |
| 09:00 | 67.8 |
| 10:00 | 93.2 |
| 11:00 | 70.4 |
| 12:00 | 53.4 |
| 13:00 | 49.6 |
| 14:00 | 50.6 |
| 15:00 | 107.7 |
| 16:00 | 5.3 |
| 17:00 | 1.3 |
| 18:00 | 1.2 |
| 19:00 | 0.7 |
The exact SQL behind every number
SELECT
formatDateTime(toStartOfHour(toTimeZone(window_start, 'America/New_York')), '%H:00') AS et_hour,
round(sum(transactions) / 1000, 1) AS spy_trade_thousands
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= toDateTime('2026-08-19 08:00:00')
AND window_start < toDateTime('2026-08-20 08:00:00')
GROUP BY et_hour
ORDER BY et_hourThe day starts at 04:00 ET with 2.4 thousand records and ends at 19:00 ET with 0.7 thousand. The regular-session hours between them tower over both.
Why full-depth options history costs an order of magnitude more
One stock is one instrument. One optionable stock is a chain of hundreds or thousands of separately quoted contracts, each with a strike, an expiration and a side, and each quoted two-sided and independently. That multiplication is the whole answer.
| symbol | contracts_priced | contracts_traded | traded_pct |
|---|---|---|---|
| SPY | 5111 | 5111 | 100 |
| TSLA | 2754 | 2754 | 100 |
| MSFT | 1997 | 1997 | 100 |
| NVDA | 1992 | 1992 | 100 |
| AAPL | 1544 | 1544 | 100 |
| KO | 475 | 475 | 100 |
The exact SQL behind every number
SELECT
underlying_symbol AS symbol,
count() AS contracts_priced,
countIf(volume > 0) AS contracts_traded,
round(100 * countIf(volume > 0) / count(), 1) AS traded_pct
FROM global_markets.options_greeks
WHERE date = '2026-08-19'
AND underlying_symbol IN ('SPY', 'AAPL', 'NVDA', 'MSFT', 'KO', 'TSLA')
GROUP BY underlying_symbol
ORDER BY contracts_priced DESCOn that session SPY carried 5111 contracts with a daily record in this dataset, and 5111 of them, 100 percent, recorded volume. Counting only the contracts that traded, one underlying is already hundreds or thousands of separately quoted instruments in a single session, against the one line a stock occupies. Each of those contracts quotes all day on every venue that lists it. Consolidated options trades are the small product here. The quote side multiplies the equity arithmetic by the chain width, and full depth multiplies it again by price level, which is the shape laid out in how big the options quote feed is. Vendors price the three tiers accordingly, and the step from trades to full depth is the expensive one.
What you can get for free, and what is missing
There are genuinely free sources. Each one is missing something specific.
- Exchange sample files. Usually a day or two of one venue's own feed, sometimes a handful of symbols, published so buyers can test a parser. Missing: continuity, and a license that covers anything beyond evaluation.
- Academic programs. Full history reaches many researchers through a university library or a research consortium at no cost to the individual. Missing: commercial use, portability after the affiliation ends, and in most cases the right to share extracts with anyone outside the named project.
- Delayed and aggregated public datasets. Minute bars, daily bars, delayed snapshots, free or nearly so. Missing: the quote side entirely, venue attribution, sequence numbers and sub-second timestamps.
That last gap is worth sizing. A minute-bar file holds at most 960 rows per symbol for a 4:00 a.m. to 8:00 p.m. day, one row per minute. The same symbol on the same day appears in the first panel above with a trade count in the millions and a quote count larger again. Bars preserve the shape of a session. They do not preserve the messages, and a question about spreads, venue routing or queue position needs the messages. For the live-feed version of the same trade-off, see what real-time market data costs.
FAQ
How much does historical tick data cost?
There is no single figure, and any number quoted without a scope attached is meaningless. Price a specific request instead: which venues, which schema, how many symbol-days, and what the license permits you to do with the output. Those four answers determine the bill, and vendor rate cards move often enough that structure is the durable thing to learn.
What is the difference between tick data and minute bars?
Tick data is the individual messages, every trade and every quote update with its own timestamp and venue. A minute bar compresses all of a minute's messages into an open, high, low, close and volume. Bars are a few hundred rows a day per symbol; ticks run into the millions.
Why is historical options data more expensive than stock data?
A stock is one instrument. An optionable stock is a chain of hundreds or thousands of contracts, each quoted separately, as the chain panel above counts. Multiply the per-instrument message rate by the chain width, then again by order book depth, and the options history sits an order of magnitude above consolidated equity trades.
Can I get historical tick data for free?
Parts of it. Exchange sample files, academic programs and public aggregated datasets are all real, and each carries a limit: coverage, eligibility, or the missing quote side. None of them substitutes for a licensed multi-year extract.
What is a redistribution license?
It is the grant that allows you to pass data, or values closely derived from it, to parties outside your organization. Internal use is the cheaper grant and the more common one. Check which you hold before publishing anything computed from licensed history.
Every panel on this page ships with the SQL that produced it, so you can see exactly how each count was taken. To size a day of your own tape before you price a vendor quote, ask the question in plain English on the Strasmore terminal.