Methodology

How the gap is reconstructed

2024-10-02 → 2026-04-20 is not real Deribit tape. It is a modeled surface, reconstructed from real trade prints and disclosed as such everywhere it is served. This page is the whole method and the whole scorecard - including the parts that fail. Nothing on it is hand-written.

What is modeled

Every currency has a real range (genuine Deribit tape, no reconstruction) and, for BTC only, a modeled range covering the historical gap. Modeled months are a bonus layer on top of the real archive, not a substitute for it.

CurrencyReal coverageModeled coverage
BTC 2021-06-01 → 2024-10-01, 2026-04-21 → ongoing 2024-10-02 → 2026-04-20
ETH 2026-04-21 → ongoing none
SOL 2026-04-27 → ongoing none

Per-field provenance within a modeled window

FieldProvenance
mark_iv anchorsReal Deribit trade prints - the only ground truth used.
volumeComputed from the trade tape (not modeled).
open_interestNULL - unavailable for this window at any defensible price. Disclosed, not estimated.
bid / askModeled spread (calibrated spread model), not observed quotes.
greeksDeribit-native computation, applied to the modeled surface.

ETH / SOL historical samples

Pre-live and sparse - these are samples, not continuous coverage.

CurrencyRangeNote
ETH 2024-01-01 → 2026-04-01 first-of-month days, 10-minute aggregated bars
SOL 2024-04-01 → 2026-04-01 first-of-month days, 10-minute aggregated bars
ETH/SOL historical samples cover first-of-month days only: 10-minute mean-aggregated bars derived from licensed third-party historical data, within the vendor's derived-data terms (≥10-minute aggregation). Field means are independent time-averages, so instantaneous ordering invariants (bid_iv < mark_iv < ask_iv) need not hold within a bar - disclosed, never clamped.

Method

The reconstruction runs in five steps: (1) recover trade-print anchors from the tape; (2) recover the forward via put-call parity; (3) invert Black-76 off that forward to get anchor IVs; (4) fit a global eSSVI surface with a calendar penalty, subject to the complete Gatheral-Jacquier no-arbitrage bounds; (5) apply a calibrated spread model to produce bid/ask around the fitted mark.

  • Mingone, A. (2022), "No arbitrage global parametrization for the eSSVI volatility surface", arXiv:2204.00312 - eSSVI parameterization and calendar-spread conditions. †
  • Gatheral, J. & Jacquier, A. (2014), "Arbitrage-free SVI volatility surfaces", Corollary 4.1 - the butterfly / no-arbitrage bound the fit is constrained to.
  • Alexander, C., Chen, D. & Imeraj, A. (2023), "Crypto quanto and inverse options", Mathematical Finance 33(4), 1005–1043 - the put-call duality underlying the forward recovery step. Deribit's index is non-tradable and settlement uses a 30-minute TWAP, so this inversion is approximate, not exact.

† The Hendriks-Martini calendar conditions used here are sufficient (not the full Mingone necessary-and-sufficient set), per Pasquazzi (2023), "eSSVI Surface Calibration", arXiv:2304.02106.

Temporal interpolation between anchors carries no theorem claim. eSSVI's guarantees are static, per-snapshot. Every emitted snapshot is numerically re-verified against the no-arbitrage bounds after fitting, and the rejection / repair / carried-dropped counters below are the published record of what that re-verification found.

Accuracy

Measured against a protocol and a set of bars fixed before the run - the hash at the foot of this page is that protocol. Core metrics block release; wing metrics are reported and never block.

SHIP Every core metric is inside its bar.

Recorded misses (7), none blocking. These are wing metrics - outside the Δ 0.25-0.75, 7-90d core - which the protocol reports and never gates release on. They are not cosmetic: a wing cell that misses its bar has its quotes nulled rather than served, so the effect shows up as absent data, never as a number we did not stand behind.

  • wing m1t0 median_abs_iv 0.0414 > 0.0400
  • wing m1t0 p90_abs_iv 0.1605 > 0.1000
  • wing m2t0 median_abs_iv 0.0938 > 0.0400
  • wing m2t0 p90_abs_iv 0.3386 > 0.1000
  • wing m2t1 median_abs_iv 0.0499 > 0.0400
  • wing m2t1 p90_abs_iv 0.2114 > 0.1000
  • wing m2t2 p90_abs_iv 0.1424 > 0.1000

Core (Δ 0.25-0.75, 7-90d) - blocks ship

MetricMeasured95% CIBarStatus
band_containment 0.4001 [0.3427, 0.4457] 0.75 FAIL
median_abs_iv 0.0108 [0.0075, 0.0159] 0.015 PASS
p90_abs_iv 0.0358 [0.0248, 0.0505] 0.04 PASS
spread_width_median_rel_err 0.3933 [0.3383, 0.4461] 0.4 PASS
recall 1.0000 [1.0000, 1.0000] 0.95 PASS

Wing (everything outside core) - reported, never blocks ship

MetricMeasured95% CIBarStatus
band_containment 0.3412 [0.3006, 0.3787] 0.5 FAIL
median_abs_iv 0.0272 [0.0220, 0.0341] 0.04 PASS
p90_abs_iv 0.1223 [0.0961, 0.1594] 0.1 FAIL
spread_width_median_rel_err 0.4671 [0.4217, 0.5116] 0.6 PASS

Wing 9-cell grid (mark_iv, moneyness × tenor)

Cellmedian_abs_errmedian CIp90_abs_errp90 CIn_daysn_rows
m0t0 0.0217 [0.0193, 0.0242] 0.0832 [0.0701, 0.0962] 9 1470279
m0t1 0.0090 [0.0067, 0.0123] 0.0278 [0.0191, 0.0415] 9 376244
m0t2 0.0270 [0.0196, 0.0377] 0.0785 [0.0573, 0.1012] 9 330811
m1t0 0.0414 [0.0369, 0.0463] 0.1605 [0.1305, 0.2035] 9 640562
m1t1 0.0163 [0.0119, 0.0220] 0.0552 [0.0356, 0.0842] 9 1421400
m1t2 0.0280 [0.0216, 0.0367] 0.0782 [0.0584, 0.0993] 9 584716
m2t0 0.0938 [0.0499, 0.1504] 0.3386 [0.1289, 0.6536] 8 59396
m2t1 0.0499 [0.0364, 0.0683] 0.2114 [0.1572, 0.2801] 9 1424130
m2t2 0.0379 [0.0309, 0.0456] 0.1424 [0.1127, 0.1788] 9 1781720

Worst days (by core median |IV error|)

DayCore median |IV err|Wing median |IV err|Recall
2024-12-01 0.0297 0.0505 1.00
2025-02-01 0.0126 0.0338 1.00
2025-06-01 0.0103 0.0280 1.00
2026-02-01 0.0085 0.0213 1.00
2025-08-01 0.0079 0.0258 1.00

Engine counters (summed over scored days)

  • snapshots_emitted12900
  • snapshots_rejected20
  • snapshots_repaired18
  • anchors_used25827
  • carried_dropped71
Mid-month accuracy is not measured. Every in-gap oracle day scored above is a post-expiry-roll 1st-of-month snapshot. Treat mid-month as an extrapolation from these day-boundary results, not an equivalent guarantee.
open_interest is never estimated. It is unavailable for the entire modeled window at any defensible price and is never backfilled. It is returned as null, not zero.

The 2021–2024 archive marks were repaired, and 11.2M were nulled

A paying customer validating the dense BTC archive against a Deribit replay found mark_price far below intrinsic value on in-the-money strikes — a put marked 0.0005 BTC that was worth 17.21. He was right, and it was ours: the importer derived mark_price as the midpoint of the vendor’s bid and ask, and for illiquid deep-ITM strikes the vendor supplies a bid and no ask at all, so that “midpoint” collapsed to a bare token bid. It had been there since the archive was imported.

Scope before the repair, counting only shortfalls over 0.01 BTC so tick noise is excluded: 19.7% of priced rows on 2023-01-01, 4.5% on 2022-06-15, 0.13% on 2024-06-15, and 0.00% on live-collected days. Worst in the early years, improving through 2024, never present in live capture.

Repaired on 2026-10-08 by re-pricing from the vendor’s own MARK_IV, which it does supply and which was sound: 48.0 million marks re-priced across 1,214 days. Where no implied volatility survived — the quote was two-sided zero, meaning no market existed — the mark is now NULL rather than a guess: 11.2 million rows. Inventing a price there would have been worse than the defect being fixed.

If you downloaded archive files before 2026-10-08, re-pull them. Those nulls are new, and so are the corrected prices. All 1,219 days were then re-read from storage and the check re-derived from scratch rather than on the repair’s own word: zero rows below intrinsic, zero read errors.

bid_price and ask_price were deliberately left alone. Those are the vendor’s reported observations; mark_price was our own derivation and was what we derived wrongly. The consequence is worth stating plainly: for ITM strikes in 2021–2024, treat the raw bid/ask as unusable — the source itself quotes a 0.0005 bid against a 1.0 ask on a call worth about 0.21 BTC. mark_price is now sound; the raw quotes around it are not.

The modeled window was rebuilt on 2026-10-12

The 2024-10 → 2026-04 reconstructed window changed twice in October 2026, and both changes are visible in files you may already hold.

2026-10-09 — the published underlying was the index, not the forward. The engine priced each option at its per-expiry forward, converted to BTC by dividing by the index, and then wrote the index into underlying_price. Both real eras either side do the opposite, which is also the exchange’s convention. The marks were never wrong, but they sat on a different basis from the underlying published beside them, so intrinsic computed from that underlying overstated put intrinsic by the carry. Corrected in place by recovering each forward algebraically from put-call parity and rescaling: no implied volatility was touched and no price was re-derived from a model.

2026-10-12 — the window was regenerated, and grew from 530 to 566 days. Two engine fixes: the reconstruction now carries its 24-hour fit across midnight (33 days previously began at 01:00, because 00:00–01:00 UTC is too thin to calibrate on its own and the engine correctly refuses to emit without a fit), and inverse options are now priced off the forward on the input side too. Every day in the window is now complete at 1,440 snapshots. The 36 added days are the last and first of each month boundary, which had been generated and validated in July but never uploaded.

If you downloaded modeled files before 2026-10-12, re-pull them. Measured against Deribit’s own reported trade volatilities, the regenerated surfaces are of comparable accuracy rather than better — mean absolute IV error moved 0.0406 → 0.0404 and the 95th percentile moved 0.1187 → 0.1225. The reasons to re-pull are the added coverage and the corrected underlying, not an accuracy gain, and we would rather say so than imply one.

open_interest is unchanged and remains null across the whole window. It is an observable, not something a surface fit can produce, and the extra days do not change that.

What a snapshot timestamp means

A chain snapshot's timestamp is the moment the collector finished gathering that cycle, not the moment it started. Every row in a cycle shares one timestamp, so a snapshot is a single point in time for range queries and joins.

This changed on 2026-10-06, and the change matters if you are backtesting. Before that date the timestamp was taken at the start of the cycle and the data was fetched afterwards, so a row was labelled with a moment slightly before its own contents existed - look-ahead bias. The error equals the cycle duration: normally about 1.5 seconds, but cycles are not reliably fast. The worst observed was 2026-09-23, when one cycle took 181 seconds and its later underlyings were stamped roughly 145 seconds early.

Rows written from 2026-10-06 onward carry the opposite, safer error: their contents may be up to one cycle older than the label. A stale quote cannot manufacture a fill that was never available; a prescient one can. Rows written before that date retain the original convention and have not been restamped - we cannot recover the fetch times that were never recorded. If your study is sensitive at the seconds scale, treat pre-2026-10-06 timestamps as the start of a window whose width is that cycle's duration rather than as an exact instant.

Analytics provenance

Every analytics response carries _meta.method_version, naming the pipeline that produced the rows. Over a window spanning more than one pipeline it reports the oldest method present: the weakest row sets what the response can be relied on for, and reporting the newest would be the more flattering and less true answer.

legacy-pre-2026-08-17 is the pipeline that produced every analytics row before the 2026-08-17 cutover - the whole archive back to 2016. Treat its surface-derived metrics as unverified. The sign of the 25-delta risk reversal is the known defect: on adjacent fortnights either side of the cutover the two methods disagree on it for most values. No timestamp was computed by both pipelines, so that is a comparison of adjacent windows and not a same-row recompute - the per-row error size is not established, and we would rather say that than imply a controlled result we do not have.

quality does not mean the same thing across that boundary, so do not filter on it alone. On rows produced after the cutover it reflects a divergence check against the options chain the surface was fitted to. On legacy-pre-2026-08-17 rows it records only whether the SVI optimiser raised an error - a surface that has lost the money still serialises perfectly and was still marked good. A legacy row reading quality: "good" is therefore a statement about the fit completing, not about the numbers being right. Filter on method_version as well.

Analytics responses also carry _meta.input_provenance, which describes what the calculation was fed rather than which code ran. real means captured market data; modeled means the input was our own reconstruction, which inside the gap window is all that exists; unknown means no provenance was recorded, which is true of every row written before 2026-10-06. Over a window it reports the weakest value present - a window mixing real and reconstructed days is not a real window, and unknown is weaker than modeled, because "nobody recorded it" tells you less than "we know it was modelled".

Access

Modeled files are opt-in: pass ?include_modeled=true to GET /v1/files/{ccy}/bulk - the only endpoint that accepts this parameter - to include modeled days in the bulk manifest (each such entry is flagged modeled: true). By default the manifest lists real coverage only.

On GET /v1/chains/{ccy}/snapshots and GET /v1/chains/{ccy}/instrument/{symbol}, ?source= filters the response body by the exact provenance tag carried in each row's source column - for example modeled_surface, live_ws, or live_rest. An unknown tag returns 400 invalid_source; there is no real/modeled shorthand.

Modeled months are not counted in coverage claims and carry no charge - a bonus layer on top of the real archive, priced at zero, disclosed everywhere it is served. What the archive itself covers is on the coverage report.