Skip to content

gjunjie/vol_surface_arbitrage_demo

Repository files navigation

Implied Volatility Surface Analytics for Market Stress Diagnostics

A transparent, reproducible research toolkit for implied volatility (IV) surface analysis: rolling-window baseline modeling, Vega-normalized residual statistics, and auditable flagging of cross-sectional IV excursions. The emphasis is on market stress detection, volatility regime adaptation (local baselines that move with the session), and explainable analytics—not on trading alpha or execution.

What this repository supports

  • Market stress & dislocation diagnostics — Measure when observed IV departs sharply from a locally fitted smile, a simple lens on cross-sectional coherence versus fragmentation in the options surface.
  • Regime-aware baselines — Minute-by-minute rolling train/test windows so the reference surface reflects recent market conditions rather than a single static day.
  • Transparent & auditable workflow — Open code, documented formulas, explicit thresholds, and sample data suitable for replication and peer review.

For the conceptual link to dislocations, explainability, and market resilience, see the short technical note: docs/TECHNICAL_NOTE.md. Deeper implementation notes: strategy/STRATEGY.md. Related literature and positioning: docs/RELATED_WORK.md. Replication and checksums: docs/REPRODUCIBILITY.md.

Disclaimer: This project is an educational and research demonstration on sample data with a simplified model. It is not investment advice, not a production risk or surveillance system, and not a guarantee of predictive performance.

Keywords: implied volatility surface; rolling baseline; Vega-normalized residuals; market stress diagnostics; reproducible research; options microstructure.

How to cite: Use the metadata in CITATION.cff (GitHub’s “Cite this repository”).

Research scope

  • In scope: Transparent definitions of baselines, residuals, and flags; illustrative runs on bundled Algoseek samples; extensions documented as future work.
  • Out of scope: Production surveillance, regulatory certification, optimized execution, and claims of predictive alpha or backtested P&L.

Project Structure

  • data/: Data files and selection documentation. Contains minute-bar options trading data for AMZN, GOOG, and TSLA.
  • optimization/: Vectorized Black-76 implied volatility and Greeks used by the pipeline. See optimization/OPTIMIZATION.md for design notes and benchmarking context.
  • strategy/: Core analytics pipeline—data processing, rolling-window IV surface fitting, residual-based diagnostics, and visualization.

Data Description

Data Source

The dataset consists of Algoseek US Options Trades minute bar data - a free sample providing options market data for demonstration and analysis purposes. The data focuses on equity options from high-volume, highly volatile stocks to ensure sufficient liquidity and rich cross-sectional IV dynamics for methodological study.

Available Data

The dataset includes minute-by-minute options trading data for the following stocks:

  • AMZN (Amazon): 4 expiry days

    • 2020-01-31, 2020-03-20, 2020-06-19, 2020-09-18
  • GOOG (Google): 7 expiry days

    • 2020-01-31, 2020-02-14, 2020-03-20, 2020-04-17, 2020-06-19, 2020-09-18, 2021-01-15
  • TSLA (Tesla): 5 expiry days

    • 2020-01-31, 2020-02-14, 2020-03-20, 2020-06-19, 2020-09-18

Data Format

Each CSV file contains minute-bar aggregated options trade data with the following columns:

  • Date: Trading date (YYYYMMDD format)
  • TimeBarStart: Minute bar start time (HH:MM format, e.g., "09:30")
  • Ticker: Underlying stock symbol
  • CallPut: Option type ("C" for Call, "P" for Put)
  • Strike: Strike price of the option
  • ExpirationDate: Option expiration date (YYYYMMDD format)
  • OpenTradePrice: Opening trade price for the minute
  • HighTradePrice: Highest trade price for the minute
  • LowTradePrice: Lowest trade price for the minute
  • CloseTradePrice: Closing trade price for the minute
  • UnderOpenBidPrice: Underlying stock opening bid price
  • UnderOpenAskPrice: Underlying stock opening ask price
  • UnderCloseBidPrice: Underlying stock closing bid price
  • UnderCloseAskPrice: Underlying stock closing ask price
  • VWAP: Volume-weighted average price
  • Volume: Number of contracts traded
  • TotalTrades: Total number of trades in the minute

For more details on data selection criteria, see data/DATA_SELECTION.md.

Methodology: Rolling IV Surface Baseline & Residual Analytics

The pipeline compares observed implied volatility to a short-horizon baseline fitted across strikes (moneyness). Large, standardized departures are treated as statistical excursions relative to that local cross-section—not as claims of “correct” fair value or profitable trades.

Core Concept

When an option’s IV diverges from the fitted smile in the test window:

  • IV below the local baselinenegative excursion (in code: Signal == 'Buy' for historical naming)
  • IV above the local baselinepositive excursion (in code: Signal == 'Sell')

The same mathematics supports diagnostic monitoring (stress-style fragmentation, localized pressure on the surface) as well as any downstream research use.

How It Works

1. Rolling Window Framework

A continuous rolling window keeps the baseline aligned with the prevailing regime:

  • Training Window: 10 minutes of data to fit the IV–moneyness model
  • Testing Window: 1 minute of data to evaluate residuals and excursions
  • Sliding Window: Advances minute-by-minute through the session

This design supports volatility regime analysis in the sense that the reference surface is re-estimated frequently, rather than assumed fixed across the day.

2. Volatility Surface Modeling

The baseline summarizes the cross-sectional relationship between moneyness and IV:

  • Moneyness: Moneyness = Strike / Forward Price (forward reflects carry and normalization across spot levels)
  • Polynomial Baseline: Cubic polynomial IV = f(Moneyness) fit on the training window
    • Captures smile/skew shape over the liquid moneyness band
    • Serves as an explicit, inspectable reference for residuals

The fitted curve is a local consensus proxy: where the surface is smooth and coordinated, residuals stay small; under stress or microstructure noise, localized or widespread excursions can appear.

3. Excursion Detection (Vega-Normalized Residuals)

Excursions are scored using Vega-normalized residuals so magnitudes are more comparable across strikes:

Residual = Actual IV - Predicted IV (from fitted model)
Vega-Normalized Residual = Residual / Vega
Z-Score = (Vega-Normalized Residual - Mean) / StdDev

Vega normalization scales by volatility sensitivity so deep OTM/ITM names are not compared on raw IV basis points alone.

Thresholds (transparent flags, default Z = 2.0):

  • Negative excursion: Z-Score ≤ -2.0 (IV materially below the local fitted smile)
  • Positive excursion: Z-Score ≥ +2.0 (IV materially above the local fitted smile)

Quality filters:

  • Moneyness range: 0.3 ≤ Moneyness ≤ 1.7 (reduces reliance on illiquid wings)
  • Minimum data quality for reliable IV
  • Minimum training points for stable polynomial fit

Illustrative Diagnostic Run (Historical Sample)

TSLA, 2020-03-20 (data/TSLA/TSLA.20200320.csv), default parameters — counts match the current code on the fingerprinted file in docs/REPRODUCIBILITY.md:

  • Windows analyzed: 378 one-minute windows
  • Windows with ≥1 negative excursion (Buy in code): 13 (3.4%)
  • Windows with ≥1 positive excursion (Sell in code): 44 (11.6%)
  • Windows with any excursion: 56 (14.8%)

These counts describe how often the simple baseline flags large standardized residuals on this dataset—they are not performance metrics, backtested returns, or evidence of economic value.

Descriptive parameter sensitivity (same file)

Not out-of-sample evaluation: the table shows how flag frequencies move when knobs change on one session. Re-run or extend via strategy/research_sensitivity.ipynb.

Setting Windows ≥1 negative (Buy) ≥1 positive (Sell) Any excursion
Default (train=10 min, z=2.0, moneyness 0.3–1.7) 378 13 (3.4%) 44 (11.6%) 56 (14.8%)
train_window_minutes=5 383 26 (6.8%) 71 (18.5%) 92 (24.0%)
train_window_minutes=15 373 10 (2.7%) 30 (8.0%) 37 (9.9%)
z_threshold=1.5 378 21 (5.6%) 51 (13.5%) 68 (18.0%)
z_threshold=2.5 378 10 (2.6%) 37 (9.8%) 46 (12.2%)
Moneyness 0.4–1.5 378 8 (2.1%) 39 (10.3%) 47 (12.4%)

Key Properties

  • Regime-responsive baselines — Rolling refitting adapts the smile to short-horizon conditions
  • Comparable cross-strike scores — Vega-normalized residuals and Z-scores
  • Explicit decision rules — Documented thresholds and filters for audit and replication
  • Liquidity-aware band — Moneyness window focuses diagnostics on more actively traded strikes
  • Visualization — IV vs. moneyness and per-window snapshots for qualitative review

Limitations & Robustness

  1. Model risk — A global cubic may miss local curvature or structural breaks; formal no-arbitrage constraints are not imposed
  2. Microstructure — Bid–ask bounce, stale prints, and aggregation can distort IV and residuals
  3. Market dynamics — Jumps, clustering, and event risk are not fully captured by a smooth polynomial baseline
  4. Data quality — Missing or sparse minutes weaken fits and can spuriously inflate excursions

For more detail, see strategy/STRATEGY.md.

Extensions for Research & Monitoring

Directions that improve diagnostic robustness and interpretability (not an exhaustive roadmap):

1. Advanced Surface Modeling

  • Local regression (LOESS) — Better local fit and outlier handling than a single global polynomial
  • Time-to-expiration weighting — Emphasize recent observations within the training window

2. Stronger Excursion Definitions

  • Liquidity-based filters — Spread, volume, and trade count gates before flagging
  • Neighbor-based residuals — Butterfly-style relative value to reduce sensitivity to global smile misspecification
  • Regime-conditioned thresholds — Calm vs. high-volatility days may warrant different Z-cutoffs

3. Execution & Cost Awareness (if bridging to tradability studies)

  • Transaction cost modeling — Spreads and slippage as filters on residual magnitude
  • Stability checks — Suppress flags when the entire surface is shifting (macro/news)

4. Analytics & Validation

  • Historical replay — Consistent assumptions across days and names
  • Residual dynamics — Persistence and half-life of excursions
  • Cross-underlying comparison — AMZN, GOOG, TSLA samples for methodological stress tests

Setup

Prerequisites

  • Python 3.8 or higher
  • pip package manager

Installation

  1. Clone the repository (if applicable) or navigate to the project directory.

  2. Create a virtual environment:

    python3 -m venv venv
    source venv/bin/activate  # On Windows: venv\Scripts\activate
  3. Install dependencies:

    pip install -r requirements.txt

Running from the repository root

Imports assume the repository root is on sys.path so that strategy and optimization resolve as top-level packages (for example from strategy.data_processing import ... and from optimization.optimized_model import ...).

  • Scripts or REPL from the project root (macOS/Linux):

    export PYTHONPATH=.
    python -c "from strategy.data_processing import load_and_prepare_data; ..."

    On Windows (PowerShell): $env:PYTHONPATH = "." before running Python.

  • Jupyter: The first cell of strategy/vol_arb_strategy.ipynb prepends the parent of the current working directory to sys.path. Start Jupyter from the strategy/ directory (so the parent is the repo root), or adjust that cell if you launch from elsewhere. Data paths in the notebook use ../data/... relative to strategy/.

If PYTHONPATH is not set and you run from a subdirectory, you may see ModuleNotFoundError: No module named 'optimization' or 'strategy'.

Usage

Main notebooks

  • strategy/vol_arb_strategy.ipynb — End-to-end workflow: load data, visualize surfaces, build rolling snapshots, filter excursions, plot windows
  • strategy/research_sensitivity.ipynb — Descriptive sensitivity of excursion counts to training length, Z-threshold, and moneyness band (same sample file as smoke tests)

Basic Workflow

from strategy.data_processing import load_and_prepare_data, prepare_rolling_data, get_clean_data_for_plotting
from strategy.rolling_strategy import build_rolling_snapshots, filter_snapshots_by_signal
from strategy.visualization import plot_iv_vs_moneyness, plot_snapshot

# 1. Load and prepare options data
df = load_and_prepare_data('data/TSLA/TSLA.20200320.csv')

# 2. Visualize the volatility surface
moneyness_clean, iv_clean = get_clean_data_for_plotting(df)
plot_iv_vs_moneyness(moneyness_clean, iv_clean)

# 3. Prepare data for rolling window analysis
df_rolling = prepare_rolling_data(df)

# 4. Build rolling window snapshots (local IV baseline per window)
snapshots = build_rolling_snapshots(
    df_rolling,
    train_window_minutes=10,  # Training window size
    test_window_minutes=1,     # Testing window size
    z_threshold=2.0            # Z-score threshold for excursions
)

# 5. Snapshot indices with excursions (code uses 'Buy' / 'Sell' for negative / positive IV excursions)
by_signal = filter_snapshots_by_signal(snapshots)
negative_excursion_indices = by_signal["buy"]
positive_excursion_indices = by_signal["sell"]

# 6. Visualize specific snapshots
plot_snapshot(snapshots[0])

Parameters

build_rolling_snapshots accepts:

  • train_window_minutes: Training window length (default: 10 minutes)
  • test_window_minutes: Test window length (default: 1 minute)
  • min_train_points: Minimum training points for a fit (default: 10)
  • moneyness_min, moneyness_max: Moneyness band for diagnostics (defaults: 0.3, 1.7)
  • z_threshold: |Z| threshold on Vega-normalized residuals (default: 2.0)

Key Files

  • optimization/optimized_model.py — Vectorized IV and Greeks (Black-76) used by data loading
  • optimization/black76_model.py — Black-76 pricing and root-finding primitives
  • optimization/profile_optimization.ipynb — Optional notebook comparing original vs. optimized pricing performance
  • strategy/rolling_strategy.py — Rolling windows, polynomial IV baseline, Vega-normalized residuals, excursion flags
  • strategy/data_processing.py — Loading, preprocessing, implied volatility construction
  • strategy/visualization.py — IV surface and snapshot plots
  • strategy/vol_arb_strategy.ipynb — Runnable demonstration notebook
  • strategy/research_sensitivity.ipynb — Parameter sensitivity tables on bundled TSLA sample
  • docs/TECHNICAL_NOTE.md — Short white paper: dislocations, explainability, resilience
  • docs/RELATED_WORK.md — Literature positioning (smiles, SVI, microstructure)
  • docs/REPRODUCIBILITY.md — Environment, data fingerprint, smoke tests
  • CITATION.cff — Software citation metadata

Development

export PYTHONPATH=.
ruff check strategy optimization tests
pytest

Licensed under the MIT License — see LICENSE.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors