Skip to content

Commit d2333fe

Browse files
committed
Fix vol surface consistency
1 parent 5c5801a commit d2333fe

9 files changed

Lines changed: 554 additions & 132 deletions

File tree

.github/copilot-instructions.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ applyTo: '/**'
1212

1313
* Always run `make lint` after code changes — runs taplo, isort, black, ruff, and mypy
1414
* Never edit `readme.md` directly — it is generated from `docs/index.md` via `make docs`
15+
* To run all tests use `make test` — runs all tests in the `tests/` directory using pytest
16+
* To run a specific test file, use `uv run pytest tests/path/to/test_file.py`
1517

1618
## Docker
1719

@@ -24,4 +26,4 @@ applyTo: '/**'
2426

2527
* The documentation for quantflow is available at `https://quantflow.quantmid.com`
2628
* Documentation is built using [mkdocs](https://www.mkdocs.org/) and stored in the `docs/` directory. The documentation source files are written in markdown format.
27-
29+
* Do not use em dashes (—) in documentation files or docstrings. Use colons, parentheses, or restructure the sentence instead.

app/volatility_surface.py

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,24 @@ def _(mo):
1919
2020
In this notebook we illustrate the use of the Volatility Surface tool in the library. We use [deribit](https://docs.deribit.com/) options on ETHUSD as example.
2121
22-
The library provide a volatility surface loader for Deribit. This code loads the surface as a [VolSurfaceLoader](api/options/vol_surface/#quantflow.options.surface.VolSurfaceLoader):
22+
The library provide a [VolSurfaceLoader](api/options/vol_surface/#quantflow.options.surface.VolSurfaceLoader) for Deribit:
2323
2424
```python
25+
import pandas as pd
2526
from quantflow.data.deribit import Deribit
2627
2728
async with Deribit() as cli:
2829
loader = await cli.volatility_surface_loader("eth", exclude_open_interest=0)
30+
31+
# build the volatility surface
32+
surface = loader.surface()
33+
# calculate black implied volatilities
34+
surface.bs()
35+
# disable outliers
36+
surface.disable_outliers()
37+
# display inputs - only options with converged implied volatility
38+
surface_inputs = surface.inputs(converged=True)
39+
pd.DataFrame([i.model_dump() for i in surface_inputs.inputs])
2940
```
3041
""")
3142
return
@@ -43,9 +54,39 @@ async def _():
4354
surface = loader.surface()
4455
# calculate black implied volatilities
4556
surface.bs()
46-
# display inputs
47-
surface_inputs = surface.inputs()
57+
# disable outliers
58+
surface.disable_outliers()
59+
# display inputs - only options with converged implied volatility
60+
surface_inputs = surface.inputs(converged=True)
4861
pd.DataFrame([i.model_dump() for i in surface_inputs.inputs])
62+
return (surface,)
63+
64+
65+
@app.cell(hide_code=True)
66+
def _(mo):
67+
mo.md(r"""
68+
##Volatility Surface
69+
""")
70+
return
71+
72+
73+
@app.cell
74+
def _(surface):
75+
surface.plot3d()
76+
return
77+
78+
79+
@app.cell(hide_code=True)
80+
def _(mo):
81+
mo.md(r"""
82+
## Term Structure
83+
""")
84+
return
85+
86+
87+
@app.cell
88+
def _(surface):
89+
surface.term_structure()
4990
return
5091

5192

docs/api/options/index.md

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,52 @@
1-
# Option Pricing
1+
# Options
22

3-
The `options` module provides classes and functions for pricing and analyzing options.
4-
The main class is the [VolSurface][quantflow.options.surface.VolSurface] class which is used to represent a volatility surface for a given asset.
5-
A volatility surface is usually created via a [VolSurfaceLoader][quantflow.options.surface.VolSurfaceLoader] object.
3+
The `options` module provides classes and functions for pricing and calibrating options.
4+
5+
## Volatility Surface
6+
7+
The central class is [VolSurface][quantflow.options.surface.VolSurface], which represents
8+
the implied volatility surface for an asset across all strikes and maturities. It holds:
9+
10+
- a [SpotPrice][quantflow.options.surface.SpotPrice] for the underlying asset
11+
- a sorted tuple of [VolCrossSection][quantflow.options.surface.VolCrossSection] objects, one per maturity
12+
13+
Each [VolCrossSection][quantflow.options.surface.VolCrossSection] contains the forward price
14+
at that maturity and a tuple of [Strike][quantflow.options.surface.Strike] objects.
15+
Each [Strike][quantflow.options.surface.Strike] holds a call and/or put as an
16+
[OptionPrices][quantflow.options.surface.OptionPrices], which in turn pairs a bid and ask
17+
[OptionPrice][quantflow.options.surface.OptionPrice].
18+
19+
A surface is typically constructed via [VolSurfaceLoader][quantflow.options.surface.VolSurfaceLoader],
20+
which accepts price inputs incrementally and builds the surface through its `surface()` method.
21+
The lower-level [GenericVolSurfaceLoader][quantflow.options.surface.GenericVolSurfaceLoader]
22+
provides the same functionality with a user-defined security type.
23+
24+
## Price Classes
25+
26+
| Class | Description |
27+
|---|---|
28+
| [Price][quantflow.options.surface.Price] | Base bid/ask price for any security |
29+
| [SpotPrice][quantflow.options.surface.SpotPrice] | Spot bid/ask price of an underlying asset |
30+
| [FwdPrice][quantflow.options.surface.FwdPrice] | Forward bid/ask price at a specific maturity |
31+
| [OptionPrice][quantflow.options.surface.OptionPrice] | Single-sided option price with implied volatility and convergence flag |
32+
| [OptionPrices][quantflow.options.surface.OptionPrices] | Paired bid and ask [OptionPrice][quantflow.options.surface.OptionPrice] for a given strike and option type |
33+
34+
## Input Classes
35+
36+
The input classes are plain data containers used to serialize and deserialize volatility surface data,
37+
for example when storing or transmitting a snapshot of the surface.
38+
39+
| Class | Description |
40+
|---|---|
41+
| [VolSurfaceInputs][quantflow.options.inputs.VolSurfaceInputs] | Top-level container: asset name, reference date, and a list of inputs |
42+
| [VolSurfaceInput][quantflow.options.inputs.VolSurfaceInput] | Base input with bid, ask, open interest and volume |
43+
| [SpotInput][quantflow.options.inputs.SpotInput] | Input for a spot price |
44+
| [ForwardInput][quantflow.options.inputs.ForwardInput] | Input for a forward price with maturity |
45+
| [OptionInput][quantflow.options.inputs.OptionInput] | Input for an option with strike, maturity, type, and optional implied vols |
46+
47+
A [VolSurface][quantflow.options.surface.VolSurface] can be round-tripped via:
48+
49+
```python
50+
inputs = surface.inputs() # VolSurface -> VolSurfaceInputs
51+
surface = surface_from_inputs(inputs) # VolSurfaceInputs -> VolSurface
52+
```

docs/api/options/vol_surface.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,30 @@
1111

1212
::: quantflow.options.surface.VolCrossSectionLoader
1313

14+
## Bid/Ask Prices
15+
16+
::: quantflow.options.surface.Price
17+
18+
::: quantflow.options.surface.SpotPrice
19+
20+
::: quantflow.options.surface.FwdPrice
21+
1422
::: quantflow.options.surface.Strike
1523

24+
::: quantflow.options.surface.OptionArrays
25+
26+
::: quantflow.options.surface.OptionMetadata
27+
1628
::: quantflow.options.surface.OptionPrice
1729

30+
::: quantflow.options.surface.OptionPrices
31+
1832
::: quantflow.options.surface.OptionSelection
1933

34+
::: quantflow.options.inputs.OptionType
35+
36+
## Vol Surface Inputs
37+
2038
::: quantflow.options.inputs.VolSurfaceInputs
2139

2240
::: quantflow.options.inputs.VolSurfaceInput

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ nav:
6464
- Double Exponential Sampling: examples/double-exponential-sampling
6565
- Hurst: examples/hurst
6666
- Supersmoother: examples/supersmoother
67+
- Volatility Surface: examples/volatility-surface
6768
- API Reference:
6869
- api/index.md
6970
- Data:

quantflow/options/bs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def black_price(
7575
"(1 for call, -1 for put)"
7676
),
7777
],
78-
) -> np.ndarray:
78+
) -> FloatArray:
7979
r"""Calculate the Black call/put option prices in forward terms
8080
from the following params
8181

quantflow/options/calibration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ class VolModelCalibration(BaseModel, ABC, Generic[M], arbitrary_types_allowed=Tr
8787
def model_post_init(self, _ctx: Any) -> None:
8888
if not self.options:
8989
self.vol_surface.bs()
90-
for option in self.vol_surface.option_prices():
90+
for option in self.vol_surface.option_prices(converged=True):
9191
key = ModelCalibrationEntryKey(option.maturity, option.strike)
9292
if key not in self.options:
9393
entry = OptionEntry(ttm=option.ttm, moneyness=option.moneyness)

0 commit comments

Comments
 (0)