Know it before you buy it.
This is the exact Parquet schema you receive — generated from the definition the collector writes against, so it cannot drift from the files themselves. Null rates are measured from a real recent file, not estimated.
| Column | Type | Null | Null rate | Zero rate | Note |
|---|---|---|---|---|---|
| timestamp | timestamp[us, tz=UTC] | required | 0.0% | — | snapshot instant, UTC |
| underlying | string | required | 0.0% | — | |
| instrument | string | required | 0.0% | — | Deribit instrument name, e.g. ETH-25DEC26-1800-C |
| strike | double | required | 0.0% | 0.0% | |
| expiry | timestamp[us, tz=UTC] | required | 0.0% | — | explicit column — never parse it out of the instrument name. Expired contracts persist in the chain briefly after expiry (up to ~10 min observed), so filter expiry > timestamp |
| type | string | required | 0.0% | — | |
| mark_iv | double | nullable | 0.0% | 0.0% | decimal, not percent: 0.65 means 65% |
| bid_iv | double | nullable | 25.93% | 0.0% | null where no IV solves — mostly deep ITM rows WITH a live bid, below intrinsic; not an illiquidity marker |
| ask_iv | double | nullable | 0.33% | 0.0% | null where no IV solves for the ask side |
| mark_price | double | nullable | 0.0% | 6.13% | 0 where the exchange published no mark |
| bid_price | double | nullable | 0.0% | 7.56% | 0 means no bid at that instant — not null. Filter > 0 |
| ask_price | double | nullable | 0.0% | 0.32% | 0 means no ask at that instant — not null. Filter > 0 |
| underlying_price | double | nullable | 0.0% | 0.0% | |
| open_interest | double | nullable | 0.0% | 20.55% | |
| volume_24h | double | nullable | 0.0% | 62.8% | |
| delta | double | nullable | 0.05% | 1.4% | exchange-published, not re-derived by us |
| gamma | double | nullable | 0.05% | 9.84% | |
| vega | double | nullable | 0.05% | 1.63% | |
| theta | double | nullable | 0.05% | 1.46% | |
| rho | double | nullable | 0.05% | 1.77% | |
| source | string | required | 0.0% | — | capture provenance. Live capture is live_ws, with occasional live_rest snapshots when the socket stalls (~0.01% of rows); reconstructed rows are modeled_surface |
| settlement_currency | string | nullable | 0.0% | — | currency Greeks and mark_price are expressed in |
| quote_currency | string | nullable | 0.0% | — | currency strikes are quoted in |
Null rates measured from 2026-09-09.parquet (761,124 rows).
Conventions worth knowing
Implied volatilities are decimals, not percentages — 0.65
means 65%. Greeks are decimals too: delta = 0.5. Both are
the exchange's own published values, captured at the snapshot instant
and never re-derived by us.
Deribit publishes 0, not null, when nothing is quoted at
that instant. We pass it through unchanged rather than normalising it,
because collapsing the two would destroy a real distinction and silently
change data customers have already reconciled.
So a price column can read as fully populated while a material share of
its rows carry no market. Filter
bid_price > 0 and ask_price > 0 before
computing a mid — a naive (bid+ask)/2 is wrong on
roughly 9% of rows, and rows that look like crossed quotes are almost
always an unquoted side rather than bad data. The zero-rate column above
is measured, not estimated.
A null means the field was absent from the exchange message altogether,
or the row pre-dates the column's introduction. On the IV columns it also
marks strikes the exchange quoted no volatility for — which is why
bid_iv carries a much higher null rate than
mark_iv. We never interpolate a value nobody quoted.
All timestamps are UTC, microsecond precision. Files partition on the
UTC day. expiry is an explicit column — you never have to
parse it out of the instrument name.
Every row carries a source tag recording how it was
captured, so live capture and the openly-modeled bridge are always
distinguishable in your own data. See methodology.
Loading it
import pandas as pd
df = pd.read_parquet("ETH-2026-07-14.parquet")
df[df.type == "call"].groupby("expiry").mark_iv.mean()
import duckdb
duckdb.sql("""
SELECT expiry, avg(mark_iv)
FROM 'ETH-*.parquet'
WHERE type = 'call'
GROUP BY expiry
""")