Status: Under Active Development | Computation Non-verified
This project fetches live SPX 0-day-to-expiry option data from Interactive Brokers, computes implied volatilities using Black-Scholes, and serves a browser dashboard with an IV smile, a projected volatility surface, and related spot / ATM metadata.
- Fetch SPX 0DTE option chain via IBKR API (strikes within ±150 of spot)
- Calculate ATM implied volatility using mid-price
- Compute IV across all strikes (OTM convention)
- Serve a Plotly-based browser dashboard over HTTP
- Stream the latest snapshot from a long-running worker to the dashboard server
- Plot 2D IV smile (strike vs implied volatility)
- Project theoretical IV forward in 30-min steps until expiry
- Plot 3D volatility surface (strike × time-to-expiry × IV)
- Compute a matched-strike call-minus-put IV spread z-score across the 0DTE chain
- Python 3.10+
- TWS or IB Gateway running
This repository vendors the IB Python API client under the pythonclient/ directory.
Install that package from the local source tree first, then install the project requirements.
Bundled IB API version: 10.44.01
cd pythonclient
pip install .
cd ..
pip install -r requirements.txtpython spx_0dte_snapshot_worker.pypython spx_0dte_http_server.pyThen open http://127.0.0.1:39999 to view the latest dashboard.
For one-off offline plot generation, you can still run:
python spx_0dte_volsurface.pypython spx_0dte_call_put_iv_zscore.pyThe dashboard is now split into two long-running processes:
spx_0dte_snapshot_worker.py: connects to IB, computes volatility data, archives JSONL history, and pushes the latest snapshot to the HTTP serverspx_0dte_http_server.py: serves the frontend fromfrontend/, stores the latest snapshot in memory, and exposes/status,/api/vol-data, and/events
Core shared logic is organized under utils/:
runtime_defaults.py: shared config defaults for worker / HTTP / standalone CLImarket_hours.py: regular-session time window logicspot_source.py: RTH SPX spot and non-RTH ES-derived synthetic spot resolutiondashboard_snapshot_store.py: archive path and JSONL persistence helpersmarket_subscription.py: reusable IB market data subscription helpersiv_calc.py: Black-Scholes pricing and IV solver helpers
Startup parameters are now loaded only from the root config.yaml:
- Worker settings:
worker: - HTTP server settings:
http_server:Includesdownloads_dir:for the archive browser root. - Standalone vol surface settings:
volsurface: - Call/put z-score settings:
zscore:
Examples:
python spx_0dte_snapshot_worker.py
python spx_0dte_http_server.py
python spx_0dte_volsurface.py
python spx_0dte_call_put_iv_zscore.py- Default refresh interval: 5 seconds
- Pushes the latest snapshot and status to the HTTP server via
POST /internal/update - Appends each successful snapshot to
record/YYYY-MM-DD/snapshots.jsonl - Only archives during the regular US session: Monday-Friday, 09:30-16:00 ET
- Uses SPX index during RTH and ES-derived synthetic SPX outside RTH when available
Example:
python spx_0dte_snapshot_worker.py- Default URL: http://127.0.0.1:39999
- Serves frontend static assets from the frontend/ directory
- Serves
/download/for browsing and downloading files underrecord/ - Stores the latest snapshot and status in memory
- Streams live dashboard updates over SSE
- Loads Plotly from CDN for browser-side rendering
Example:
python spx_0dte_http_server.pySnapshot files are stored like this:
frontend/
index.html
app.js
styles.css
config.yaml
utils/
iv_calc.py
config_loader.py
runtime_defaults.py
market_hours.py
spot_source.py
plotting.py
dashboard_snapshot_store.py
market_subscription.py
record/
2026-03-23/
snapshots.jsonl
API endpoints:
/statusreturns refresh status and archive metadata/api/vol-datareturns the latest volatility snapshot JSON used by the dashboard/download/browses archive folders and downloads files from the configured record root
Note: the current market-hours gate checks weekday and 09:30-16:00 ET. It does not yet exclude exchange holidays.