Data sources and access boundaries¶
OCA normalises feeds but does not grant data rights. Empirical datasets remain outside the repository until their redistribution terms are reviewed.
Canonical data catalogue and storage¶
Raw provider inputs and normalized option caches have separate roots. OCA resolves raw data from
OCA_DATA_PATH and normalized caches from OCA_CACHE_PATH; when unset, a source checkout uses its
ignored data/ and resources/ directories. Code must use
option_chain_analytics.local_path.get_resource_path() and get_cache_path() rather than embed a
workstation path.
<OCA_DATA_PATH>/
├── cboe_options/
│ └── provider source files
├── tardis/ # provider hourly source files
├── deribit/ # provider snapshots and aggregate files
└── bbg_vols/ # source surfaces, not option chains
<OCA_CACHE_PATH>/
├── cboe_options/
│ ├── spx_options_oca.parquet
│ └── vix_options_oca.parquet
├── tardis/
│ ├── btc_options_oca.parquet
│ └── eth_options_oca.parquet
└── thetadata_options/
└── <ticker-lower>/
├── manifest.json
├── options/YYYY-MM.parquet
└── spot/YYYY-MM.parquet
The following catalogue is the supported path from stored data to OptionsDataDFs:
Data |
Canonical storage path |
Loader |
Container construction |
|---|---|---|---|
CBOE SPX/VIX EOD |
|
|
|
Tardis BTC/ETH EOD |
|
|
|
Tardis BTC/ETH hourly |
provider files under |
|
|
Deribit BTC/ETH snapshots |
provider files under |
|
|
ThetaData equity/ETF EOD |
|
|
loader returns |
Deterministic fixture |
no storage; generated in memory |
|
loader returns |
Bloomberg BVOL surfaces, derived ATM/skew CSVs, and any retained Yahoo files are not
OptionsDataDFs sources. They must not be passed through a legacy or inferred adapter. The
workstation-local ignored data/README.md records physical junction targets, observed coverage,
file sizes, and datasets retained only as source material.
To inspect the resolved root in any environment:
from option_chain_analytics.local_path import get_cache_path, get_resource_path
print(get_resource_path())
print(get_cache_path())
Install only the integration required by the study, for example
pip install "option-chain-analytics[cboe]". The available extras are cboe, deribit,
bloomberg, and thetadata; all installs every optional integration available for the
running Python version. The official ThetaData client requires Python 3.12 or newer.
Source path |
Underlyings / local coverage |
Current OCA status |
Public replication use |
|---|---|---|---|
Deterministic simulation |
|
Supported and release-gating |
Yes; generated locally, no download. |
CBOE fitted chains |
SPX: 2015-01-02–2023-11-08; VIX: 2015-01-02–2024-05-31 |
|
No files distributed; users must provide lawful local access. |
Tardis hourly chains |
BTC/ETH: 2019-03-30–2024-05-06 UTC on the maintainer’s local archive |
Hourly source through |
No files distributed; provider terms apply. |
Deribit snapshots |
BTC/ETH: 2023-10-27–2024-02-13 UTC on the maintainer’s local archive |
Supported by |
Historical archive not distributed. |
ThetaData national EOD |
US equity/ETF option roots available to the authenticated account |
|
Provider subscription and data terms apply; no responses are distributed. |
Bloomberg BVOL |
SPX daily volatility surfaces: 2005-01-03–2024-06-17 locally |
Input exists; option-price mapping and maturity rolling are TODO |
Bloomberg access required; synthetic output must be labelled, not represented as observed prices. |
Only workflows listed in the
examples/README.md
guide are maintained as runnable examples. In particular, OCA does not ship a Bloomberg BVOL
example until the synthetic-option mapping and maturity-roll policy are defined.
CBOE conventions¶
The consolidated SPX dataset contains SPXW contracts and uses PM settlement at 16:00 New York
time. VIX/VIXW uses the morning Special Opening Quotation at 09:30 New York time; its last trading
day is normally the preceding business day. OCA recomputes expiry and time to maturity from these
product policies instead of preserving the legacy files’ common 16:15 dte convention.
The legacy fitted impl_fw, impl_df, mid_vols, delta, and vega columns are not trusted by
the cache converter. For every observation/expiration, OCA replaces the old fitted mark with the
bid/ask midpoint, robustly refits forward and discount from call-put parity, and calculates mark,
bid, and ask implied volatilities plus mark delta and vega with vanilla-option-pricers. Expiries
without sufficient aligned call/put quotes are omitted. The files do not contain an independent
spot series.
Use build_local_cboe_options_cache(ticker='SPX') and
build_local_cboe_options_cache(ticker='VIX') once to materialize normalized Zstandard-compressed
Parquet files. Parquet is used instead of CSV because it preserves timezone-aware timestamps and
numeric dtypes, supports predicate filtering by observation time, and is substantially smaller and
faster for these multi-million-row panels. The loader prefers a valid cache automatically. Each
file contains an OCA schema version and source size/modification fingerprint; a changed source or
schema requires an explicit overwrite=True rebuild.
Build both reusable research caches from the consolidated local datasets through the public API:
from option_chain_analytics.data.cboe import build_local_cboe_options_cache
for ticker in ('SPX', 'VIX'):
build_local_cboe_options_cache(
ticker=ticker,
local_path='/path/to/cboe_options',
overwrite=True,
)
With the default provider directories, this writes spx_options_oca.parquet and
vix_options_oca.parquet under $OCA_CACHE_PATH/cboe_options/. A custom --cboe-dir retains the
previous co-located source/cache behavior. Cache metadata fingerprints the source and records the
OCA schema, settlement policy, and analytics policy. The default cache inputs are the consolidated
daily spx_options.feather and vix_options.feather. The much larger annual intraday archives are
deliberately not collapsed into these files; a future partitioned intraday cache can preserve their
full timestamp granularity.
For research returns, supply a separately licensed and time-aligned spot series. The
is_use_front_forward_as_spot=True switch is a visualisation-only proxy and should be identified as
such in figures and tables.
Standardized local EOD caches¶
SPX, VIX, BTC, and ETH caches use the same physical Parquet schema: contract,
underlying_index, mat_id, and optiontype are Arrow strings; exchange_time and expiry are
nanosecond UTC timestamps; every other SliceColumn is float64. This deliberately converts CBOE
integer sizes/strikes and Tardis float32 fields to one nullable numerical representation.
BTC and ETH are sampled from the hourly Tardis archive at exactly 08:00 UTC. Missing snapshots are
not replaced with earlier or later rows. Their inverse option prices remain in BTC/ETH units,
usd_multiplier is the expiry forward, spot_price is the exact-time Deribit index price, and the
legacy Tardis discount convention is one. The perpetual index is preferred for spot; when it is
absent, an exact-time index_price row from the option feed is used, never a value from another
timestamp. The source BTC/ETH histories cover 2019-03-30 08:00 UTC through 2024-05-05 08:00 UTC
after daily sampling.
Build or rebuild the standardized caches through their provider-specific public functions:
from option_chain_analytics.data.cboe import build_local_cboe_options_cache
from option_chain_analytics.data.tardis import build_local_tardis_eod_options_cache
for ticker in ('SPX', 'VIX'):
build_local_cboe_options_cache(
ticker=ticker,
local_path='/path/to/cboe_options',
overwrite=True,
)
for ticker in ('BTC', 'ETH'):
build_local_tardis_eod_options_cache(
ticker=ticker,
local_path='/path/to/tardis',
daily_hour_utc=8,
overwrite=True,
)
With default provider directories, the four files are written under
$OCA_CACHE_PATH/{cboe_options,tardis}/. Custom source directories retain co-located caches.
Metadata stores the common schema and dtype policy plus provider-specific timestamp, settlement,
analytics, price, and source-fingerprint policies. Use load_local_tardis_eod_options_data for
BTC/ETH; it returns the same chain_ts, spot_data, and ticker constructor payload as the CBOE
loader.
ThetaData EOD conventions¶
Install option-chain-analytics[thetadata] on Python 3.12 or newer. The loader delegates
authentication to the official client; credentials and API keys are never stored by OCA. The
credential-free path in examples/fetch_thetadata_eod.py injects a deterministic client with the
same method contract and does not contact ThetaData, while --live uses the provider client and
requires the Theta Terminal/account.
For example, display AAPL ATM volatility for a specified historical report date and expiration:
python examples/fetch_thetadata_eod.py --live --ticker AAPL \
--value-date 2026-07-24 --expiration 2026-08-21 --metric atm
Select --metric skew --delta 0.25 for OCA’s 25-delta call-minus-put volatility slope over
log-strike distance, or --metric both to print both values. The expiration is required because an
ATM volatility or skew is maturity-specific.
load_thetadata_eod_options_data fetches one report date and either explicit expirations or the
provider’s filtered expiration listing. Its scope is US equity and ETF options. ThetaData’s
date-only expiration is interpreted as 16:00 America/New_York and converted to UTC. Do not use the
adapter for SPX, VIX, or another index until that product’s AM/PM settlement and expiry timestamp
are represented explicitly.
The mapper retains separate call and put contracts, USD bid/mid/ask prices, sizes, and report-period
volume. Live loaders request ThetaData’s SOFR EOD history by default, convert the percentage rate to
a flat continuously compounded discount factor, and robustly infer the forward from joint call/put
quotes. Pass rate_symbol=None to infer both terms from parity, or pass a different supported rate
symbol. Parity fitting uses inverse-spread weights, Huber reweighting, and explicit discount bounds.
All bid, mark, and ask implied volatilities and mark Greeks come from vanilla-option-pricers.
Expiries without sufficient parity inputs are omitted instead of receiving a disguised spot proxy.
The option EOD endpoint does not supply open interest, so that field remains NaN.
The SOFR choice, point-in-time rate alignment, staleness limit, US-equity/ETF scope, expiry time,
and provider-level discount bounds belong to the ThetaData adapter. The reusable parity regression
is provider-neutral and lives in option_chain_analytics.utils.forward_discount.
Build resumable monthly cache partitions with:
python examples/build_thetadata_eod_cache.py --ticker SPY --start-date 2023-06-01
load_thetadata_eod_cache(cache_root, start_date=..., end_date=...) reads only overlapping
monthly partitions and returns the same OptionsDataDFs container as the live loaders. The
cache uses parity-only rate fitting consistently across the free history and remains ignored local
vendor data.
Reuse the cache for plots and a chain report without contacting ThetaData:
python examples/fetch_thetadata_atm_timeseries.py --metric atm --output spy_atm.png
python examples/fetch_thetadata_atm_timeseries.py --metric skew --output spy_skew.png
python examples/run_chain_report.py --date 2026-07-17 --output spy_chain_report.pdf
The option created field is the observation time. The underlying stock report keeps its own
timestamp and is joined to an option row only when it was available at or before the option report;
a later close is never backward-filled. Normalized metadata records the source, price convention,
expiry convention, and spot-alignment policy. Optional local Parquet caches contain normalized
responses and are never distributed by OCA.
Local layout¶
Set OCA_DATA_PATH for raw provider inputs and OCA_CACHE_PATH for normalized reusable chains.
With no overrides, a source checkout uses ignored data/ and resources/. Never commit raw vendor
files, normalized caches, credentials, machine-specific paths, or generated empirical outputs.
Replication instructions should name the provider, access date, transformations, coverage,
timezone, and missing-data policy even when the underlying file cannot be redistributed.