How Much Does It Cost to Trade Options?
Options commissions may be zero, but the bid-ask spread is real. See the median cost to trade SPY, QQQ, IWM, GLD, and TSLA options, in basis points.
Commissions on listed options are zero at most brokerages, but every marketable options order still pays the bid-ask spread — the gap between the best price a buyer will pay and the best price a seller will accept. Options usually trade at far lower dollar prices than the stock they reference, so the same cents-wide gap is a much larger share of the trade. On 2026-07-02, SPY options (every 2026-expiry contract) quoted a median spread of 80.97 basis points during regular hours, while SPY stock itself quoted 0.27 bps — a gap of roughly 299.9×. Every figure below is measured from the consolidated options quote and trade tapes, with the exact SQL behind each number attached.
Why options spreads look different from stock spreads
Consider a stock quoted $745.00 bid / $745.02 ask. The two-cent spread is about 0.27 bps of the share price. An at-the-money call on the same stock might be quoted $7.20 bid / $7.30 ask — a ten-cent spread, which works out to roughly 138 bps of the $7.25 midpoint. The option is wider in cents, and hundreds of times wider as a share of the price actually paid. The option’s low dollar price does the mechanical work: ten cents is a small amount in absolute terms and a large percentage of a $7.25 contract.
The professional unit for comparing costs across instruments is the basis point (bp) — one hundredth of one percent. A standard option contract covers 100 shares of the underlying, so the dollar consequence of a trade scales with the underlying, but the spread is measured against the option’s own quoted price. That is the unit used throughout this page.
SPY options vs. SPY stock: a head-to-head
SPY is the most liquid options product in the US, and even there the cost gap is dramatic. The panel below puts SPY options and SPY stock side by side on the same session: quote traffic, executed trades, and the median quoted spread of each.
The exact SQL behind every number
WITH
opt_q AS (
SELECT
count() AS opt_updates,
quantileDeterministic(0.5)((toFloat64(ask_price) - toFloat64(bid_price)) / ((toFloat64(ask_price) + toFloat64(bid_price)) / 2), cityHash64(ticker, sip_timestamp)) AS opt_median_spread_ratio
FROM global_markets.cache_options_quotes
WHERE sip_timestamp >= '2026-07-02 13:30:00' AND sip_timestamp < '2026-07-02 20:00:00'
AND ticker >= 'O:SPY26' AND ticker < 'O:SPY27'
AND bid_price > 0 AND ask_price > 0 AND ask_price > bid_price
),
stock_q AS (
SELECT
count() AS stock_updates,
quantileDeterministic(0.5)((toFloat64(ask_price) - toFloat64(bid_price)) / ((toFloat64(ask_price) + toFloat64(bid_price)) / 2), cityHash64(ticker, sip_timestamp)) AS stock_median_spread_ratio
FROM global_markets.cache_stocks_quotes
WHERE sip_timestamp >= '2026-07-02 13:30:00' AND sip_timestamp < '2026-07-02 20:00:00'
AND ticker = 'SPY'
AND bid_price > 0 AND ask_price > 0 AND ask_price > bid_price
),
opt_t AS (
SELECT count() AS opt_trades FROM global_markets.options_trades
WHERE sip_timestamp >= '2026-07-02 13:30:00' AND sip_timestamp < '2026-07-02 20:00:00'
AND ticker >= 'O:SPY26' AND ticker < 'O:SPY27'
),
stock_close AS (
SELECT round(argMax(toFloat64(close), window_start), 2) AS spy_close
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY' AND window_start >= '2026-07-02 13:30:00' AND window_start < '2026-07-02 20:00:00'
)
SELECT
'2026-07-02' AS session_date,
opt_q.opt_updates AS spy_opt_updates,
stock_q.stock_updates AS spy_stock_updates,
round(opt_q.opt_updates / stock_q.stock_updates, 1) AS opt_to_stock_update_ratio,
opt_t.opt_trades AS spy_opt_trades,
round(opt_q.opt_updates / opt_t.opt_trades, 1) AS quotes_per_trade,
round(opt_q.opt_median_spread_ratio * 10000, 2) AS spy_opt_median_spread_bps,
round(stock_q.stock_median_spread_ratio * 10000, 2) AS spy_stock_median_spread_bps,
round(opt_q.opt_median_spread_ratio / stock_q.stock_median_spread_ratio, 1) AS ratio_opt_to_stock_spread,
stock_close.spy_close AS spy_underlying_close
FROM opt_q CROSS JOIN stock_q CROSS JOIN opt_t CROSS JOIN stock_closeThe median SPY options spread of 80.97 bps means a round-trip market order — buying at the ask and later selling at the bid — gives up roughly the full quoted spread relative to the midpoint, about half on each side of the trade. The same round trip in SPY stock gives up roughly 0.27 bps. The quote traffic tells the same liquidity story from another angle: market makers printed 256.5 SPY option quote updates for every executed SPY options trade, repricing thousands of strike-and-expiry combinations tick by tick.
The SPY options spread distribution: it is not one number
A median is useful, but the spread an individual trader pays depends on the contract. Near-the-money, near-expiration SPY options tend to quote the tightest; far out-of-the-money and far-dated contracts can be much wider. The panel below shows the full distribution across valid two-sided SPY option quotes in the session.
The exact SQL behind every number
WITH opts AS (
SELECT
(toFloat64(ask_price) - toFloat64(bid_price)) / ((toFloat64(ask_price) + toFloat64(bid_price)) / 2) * 10000 AS spread_bps,
cityHash64(ticker, sip_timestamp) AS det
FROM global_markets.cache_options_quotes
WHERE sip_timestamp >= '2026-07-02 13:30:00' AND sip_timestamp < '2026-07-02 20:00:00'
AND ticker >= 'O:SPY26' AND ticker < 'O:SPY27'
AND bid_price > 0 AND ask_price > 0 AND ask_price > bid_price
)
SELECT
round(quantileDeterministic(0.10)(spread_bps, det), 2) AS p10_bps,
round(quantileDeterministic(0.25)(spread_bps, det), 2) AS p25_bps,
round(quantileDeterministic(0.50)(spread_bps, det), 2) AS median_bps,
round(quantileDeterministic(0.75)(spread_bps, det), 2) AS p75_bps,
round(quantileDeterministic(0.90)(spread_bps, det), 2) AS p90_bps,
count() AS valid_two_sided_quotes
FROM optsThe middle half of SPY option quotes fell between 49.65 bps and 147.12 bps. One quote in ten was tighter than 35.51 bps, and one in ten was wider than 316.51 bps. The wide tail tracks illiquid strikes and far-dated expiries — exactly the contracts a casual buyer is most likely to stumble into.
How cost varies across popular products
SPY is the benchmark, but not every options product quotes as tightly. The panel below measures the median regular-hours quoted spread, in basis points, across five widely traded option roots: three index ETFs (SPY, QQQ, IWM), a gold ETF (GLD), and a single stock with deep options liquidity (TSLA). Each root is filtered to its 2026-expiry ticker range so the query prunes the (ticker, sip_timestamp) index, and the rows are listed alphabetically so each product keeps a fixed position.
The exact SQL behind every number
SELECT
root,
round(count() / 1e6, 1) AS quote_updates_millions,
round(quantileDeterministic(0.5)(spread_bps, det), 2) AS median_spread_bps,
round(quantileDeterministic(0.5)(width_cents, det), 2) AS median_width_cents
FROM (
SELECT 'SPY' AS root, (toFloat64(ask_price) - toFloat64(bid_price)) / ((toFloat64(ask_price) + toFloat64(bid_price)) / 2) * 10000 AS spread_bps, (toFloat64(ask_price) - toFloat64(bid_price)) * 100 AS width_cents, cityHash64(ticker, sip_timestamp) AS det
FROM global_markets.cache_options_quotes
WHERE sip_timestamp >= '2026-07-02 13:30:00' AND sip_timestamp < '2026-07-02 20:00:00'
AND ticker >= 'O:SPY26' AND ticker < 'O:SPY27'
AND bid_price > 0 AND ask_price > 0 AND ask_price > bid_price
UNION ALL
SELECT 'QQQ' AS root, (toFloat64(ask_price) - toFloat64(bid_price)) / ((toFloat64(ask_price) + toFloat64(bid_price)) / 2) * 10000 AS spread_bps, (toFloat64(ask_price) - toFloat64(bid_price)) * 100 AS width_cents, cityHash64(ticker, sip_timestamp) AS det
FROM global_markets.cache_options_quotes
WHERE sip_timestamp >= '2026-07-02 13:30:00' AND sip_timestamp < '2026-07-02 20:00:00'
AND ticker >= 'O:QQQ26' AND ticker < 'O:QQQ27'
AND bid_price > 0 AND ask_price > 0 AND ask_price > bid_price
UNION ALL
SELECT 'IWM' AS root, (toFloat64(ask_price) - toFloat64(bid_price)) / ((toFloat64(ask_price) + toFloat64(bid_price)) / 2) * 10000 AS spread_bps, (toFloat64(ask_price) - toFloat64(bid_price)) * 100 AS width_cents, cityHash64(ticker, sip_timestamp) AS det
FROM global_markets.cache_options_quotes
WHERE sip_timestamp >= '2026-07-02 13:30:00' AND sip_timestamp < '2026-07-02 20:00:00'
AND ticker >= 'O:IWM26' AND ticker < 'O:IWM27'
AND bid_price > 0 AND ask_price > 0 AND ask_price > bid_price
UNION ALL
SELECT 'GLD' AS root, (toFloat64(ask_price) - toFloat64(bid_price)) / ((toFloat64(ask_price) + toFloat64(bid_price)) / 2) * 10000 AS spread_bps, (toFloat64(ask_price) - toFloat64(bid_price)) * 100 AS width_cents, cityHash64(ticker, sip_timestamp) AS det
FROM global_markets.cache_options_quotes
WHERE sip_timestamp >= '2026-07-02 13:30:00' AND sip_timestamp < '2026-07-02 20:00:00'
AND ticker >= 'O:GLD26' AND ticker < 'O:GLD27'
AND bid_price > 0 AND ask_price > 0 AND ask_price > bid_price
UNION ALL
SELECT 'TSLA' AS root, (toFloat64(ask_price) - toFloat64(bid_price)) / ((toFloat64(ask_price) + toFloat64(bid_price)) / 2) * 10000 AS spread_bps, (toFloat64(ask_price) - toFloat64(bid_price)) * 100 AS width_cents, cityHash64(ticker, sip_timestamp) AS det
FROM global_markets.cache_options_quotes
WHERE sip_timestamp >= '2026-07-02 13:30:00' AND sip_timestamp < '2026-07-02 20:00:00'
AND ticker >= 'O:TSLA26' AND ticker < 'O:TSLA27'
AND bid_price > 0 AND ask_price > 0 AND ask_price > bid_price
)
GROUP BY root
ORDER BY root ASCThe index ETFs own the tight end of the board: SPY quoted a median spread of 80.97 bps, QQQ 123.71 bps, and IWM 130.72 bps. At the wide end, TSLA options quoted 309.93 bps and GLD options 786.75 bps — a different cost regime entirely. The quote-updates column (in millions) tells the companion story: the most heavily quoted products sit at the tight end of the board.
The 0DTE and weekly effect: shorter life, wider spread
Contracts with less time left tend to trade at lower dollar prices, which mechanically raises the spread in basis points even when the gap in cents stays small. The panel below groups near-the-money SPY option quotes (strikes 730–760) by expiration date — every 2026 expiry that printed at least one million quote updates in the session, in calendar order.
The exact SQL behind every number
WITH opts AS (
SELECT
toFloat64(ask_price) - toFloat64(bid_price) AS width,
(toFloat64(ask_price) + toFloat64(bid_price)) / 2 AS mid,
substring(ticker, -15, 6) AS expiry_code,
toUInt32OrZero(substring(ticker, -8)) / 1000 AS strike,
cityHash64(ticker, sip_timestamp) AS det
FROM global_markets.cache_options_quotes
WHERE sip_timestamp >= '2026-07-02 13:30:00' AND sip_timestamp < '2026-07-02 20:00:00'
AND ticker >= 'O:SPY26' AND ticker < 'O:SPY27'
AND bid_price > 0 AND ask_price > 0 AND ask_price > bid_price
AND strike BETWEEN 730 AND 760
)
SELECT
expiry_code,
round(count() / 1e6, 1) AS quote_updates_millions,
round(quantileDeterministic(0.5)(width / mid * 10000, det), 2) AS median_spread_bps,
round(quantileDeterministic(0.5)(width * 100, det), 2) AS median_width_cents
FROM opts
GROUP BY expiry_code
HAVING count() >= 1000000
ORDER BY expiry_code ASCThe same-day contract — expiry code 260702, the 0DTE — showed a median spread of 113.64 bps on a median width of just 2 cents. The longest-dated expiry over the bar, 261231, quoted wider in cents (11) yet materially tighter in basis points, at 37.16 bps. That is the core lesson of options trading costs: a one- or two-cent spread is not automatically cheap when the option itself trades for a few dollars. What 0DTE options are explains the mechanics of same-day contracts.
What the trade-size data says about who pays these costs
Options trade in contracts, and one standard contract covers 100 shares. The median executed options trade on 2026-07-02 was just 1 contract; even the 90th percentile print was only 10 contracts. Most options trades are small, and the retail-sized trader is the one most exposed to the quoted spread — a large institutional order can often negotiate price improvement or slice itself across time.
The exact SQL behind every number
WITH trades AS (
SELECT toFloat64(size) AS size FROM global_markets.options_trades
WHERE sip_timestamp >= '2026-07-02 13:30:00' AND sip_timestamp < '2026-07-02 20:00:00'
)
SELECT
round(quantileExact(0.50)(size), 0) AS median_contracts,
round(quantileExact(0.90)(size), 0) AS p90_contracts,
round(avg(size), 1) AS avg_contracts,
count() AS total_prints
FROM tradesFAQ
Are options more expensive to trade than stocks?
Usually yes, measured as a share of the traded price. A deeply liquid ETF like SPY pays a quoted spread well under one basis point on the stock itself; the same underlying’s options routinely pay tens of basis points. The dollar amount depends on the option’s price and the number of contracts, but the spread as a percentage of the option’s value is almost always larger than the stock’s.
Why are 0DTE options so wide in basis points?
Same-day and weekly options often trade at low dollar prices — sometimes under $1.00 — near the end of their life. A one- or two-cent spread on a $0.50 option is 2–4% of the price, or 200–400 bps. The cents look small; the percentage cost is not. That is why traders compare spreads in basis points, not cents.
Do commissions matter more than the spread?
For a single-lot retail trade, the spread usually dominates. A $1.00 / $1.05 quote costs $5.00 per contract on a full round trip (100 shares per contract) before any commission. On low-priced or wide-spread products, the spread alone can exceed any plausible commission.
Can I avoid the spread by using limit orders?
A limit order inside the spread can fill for less than the full spread, but it is not guaranteed to fill. A marketable order pays the spread by definition. The spread is the price of immediacy, not a fee your broker charges.
Which options products have the tightest spreads?
On this page’s measurements, the big index ETFs — SPY, QQQ, IWM — quote the tightest medians, and they also carry the heaviest quote traffic. Commodity ETFs (GLD) and single-stock options can quote much wider. The spread varies contract by contract — same underlying, different strike and expiry — so a single median hides a lot of variation.
Data notes
All timestamps are stored in UTC; regular hours on July 2, 2026 are filtered as sip_timestamp >= '2026-07-02 13:30:00' AND sip_timestamp < '2026-07-02 20:00:00' (9:30 am–4:00 pm ET). Spread statistics use only valid two-sided quotes (bid_price > 0, ask_price > 0, ask_price > bid_price), cast Decimal prices to Float64 before division, and use deterministic median estimators (quantileDeterministic, keyed by a hash of ticker and timestamp) so regeneration reproduces identical figures. The census below counts every SPY-options record in the window and shows how much of the raw feed those valid two-sided quotes represent.
Quote-quality census and full methodology
The exact SQL behind every number
WITH opts AS (
SELECT
bid_price,
ask_price
FROM global_markets.cache_options_quotes
WHERE sip_timestamp >= '2026-07-02 13:30:00' AND sip_timestamp < '2026-07-02 20:00:00'
AND ticker >= 'O:SPY26' AND ticker < 'O:SPY27'
)
SELECT
count() AS total_updates,
countIf(bid_price > 0 AND ask_price > 0 AND ask_price > bid_price) AS valid_two_sided,
round(100.0 * countIf(bid_price > 0 AND ask_price > 0 AND ask_price > bid_price) / count(), 2) AS valid_pct,
countIf(bid_price = 0 OR ask_price = 0) AS one_sided,
round(100.0 * countIf(bid_price = 0 OR ask_price = 0) / count(), 2) AS one_sided_pct,
countIf(bid_price > 0 AND ask_price > 0 AND ask_price <= bid_price) AS locked_or_crossed,
round(100.0 * countIf(bid_price > 0 AND ask_price > 0 AND ask_price <= bid_price) / count(), 2) AS locked_or_crossed_pct
FROM optsMore than 99.94% of SPY option quote records in the session were valid two-sided quotes; one-sided records were 0.06% of the feed, and locked or crossed records were negligible. Every spread number above is computed on the valid two-sided subset — the cost a trader could actually observe in the NBBO.
- Market data source: consolidated OPRA-style options quote tape (
global_markets.cache_options_quotes), the corresponding stock quote tape, and the consolidated options trade tape (global_markets.options_trades; the trade-size panel deliberately covers the whole tape, not just SPY). - OCC ticker format:
O:+ root + six-digit expiry (YYMMDD) +C/P+ seven-digit strike ×1000. The 0DTE panel parses expiry and strike from the ticker; spread calculations aggregate calls and puts together. Each root’s filter covers its 2026-expiry range (O:SPY26..O:SPY27and equivalents), which keeps every scan pruned on the (ticker, sip_timestamp) index. - Spread definition:
(ask − bid) / midpoint × 10,000, in basis points, on valid two-sided quotes only. - Medians and percentiles:
quantileDeterministicreservoir estimators keyed bycityHash64(ticker, sip_timestamp)— bounded memory, and identical output on every regeneration. - Underlying close: last regular-hours minute bar from
delayed_stocks_minute_aggs. - Session window: 13:30–20:00 UTC, checked against observed SPY minute bars rather than calendar arithmetic.
- Pinned session: July 2, 2026 — a completed full session comfortably behind the warehouse’s ~1–2 day ingest lag at authoring time (July 9, 2026). Date literals are fixed, so regeneration reproduces the same figures.
Curious what a specific contract costs? Every panel above is a stored query — run them, or your own variation, on the Strasmore terminal. For more on the mechanics, see the cost to trade stocks, what a bid-ask spread is, 0DTE options, the size of the options quote feed, and options volume vs. open interest.