Skip to content

Commit 7d29f5c

Browse files
FlyCapitalclaude
andcommitted
Add vol_surface_raw() for GET /v1/vol-surface/raw (v0.4.0)
New client method + RawVolSurface/RawSurfaceExpiry models for the public raw market-quoted surface endpoint (strikes[] + mkt_vol[] per listed expiry, no SABR params). README method table + version bumped to 0.4.0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 70a9f6d commit 7d29f5c

5 files changed

Lines changed: 84 additions & 3 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ That's it. The client is typed end-to-end, so your IDE autocompletes every field
6161
| `cv.vol_index(...)` | `GET /v1/vol-index` | Daily IV index time series (CryptoVIX-style) |
6262
| `cv.vol_surface(...)` | `GET /v1/vol-surface` | One SABR-interpolated vol point |
6363
| `cv.vol_surface_bulk(...)` | `POST /v1/vol-surface/bulk` | Many points in one round-trip — efficient |
64+
| `cv.vol_surface_raw(...)` | `GET /v1/vol-surface/raw` | Raw market-quoted surface (strike ladders, pre-fit) — PRO and ULTRA |
6465
| `cv.vol_history(...)` | `GET /v1/vol-history` | Constant-maturity historical IV for backtests |
6566
| `cv.spot_history(...)` | `GET /v1/spot-history` | Daily spot price time series per session |
6667
| `cv.realized_vol(...)` | `GET /v1/realized-vol` | Rolling annualized RV (√365) from spot log-returns |

cryptovol/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
BulkResultItem,
2828
BulkVolResponse,
2929
Greeks,
30+
RawSurfaceExpiry,
31+
RawVolSurface,
3032
RealizedVolPoint,
3133
RealizedVolResponse,
3234
SpotHistoryPoint,
@@ -38,7 +40,7 @@
3840
VolSurfacePoint,
3941
)
4042

41-
__version__ = "0.3.0"
43+
__version__ = "0.4.0"
4244

4345
__all__ = [
4446
"CryptoVol",
@@ -59,6 +61,8 @@
5961
"VolSurfacePoint",
6062
"BulkVolResponse",
6163
"BulkResultItem",
64+
"RawVolSurface",
65+
"RawSurfaceExpiry",
6266
"VolHistoryResponse",
6367
"VolHistoryPoint",
6468
"SpotHistoryResponse",

cryptovol/client.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
)
3939
from .models import (
4040
BulkVolResponse,
41+
RawVolSurface,
4142
RealizedVolResponse,
4243
SpotHistoryResponse,
4344
VolHistoryResponse,
@@ -48,7 +49,7 @@
4849
DEFAULT_BASE_URL = "https://cryptovol-api-nbakzshi6q-uc.a.run.app"
4950
DEFAULT_TIMEOUT = 30.0
5051
DEFAULT_MAX_RETRIES = 3
51-
DEFAULT_USER_AGENT = "cryptovol-python/0.3.0"
52+
DEFAULT_USER_AGENT = "cryptovol-python/0.4.0"
5253

5354
StrikeType = Literal["strike", "moneyness", "delta"]
5455
OptionType = Literal["C", "P"]
@@ -272,6 +273,50 @@ def vol_surface_bulk(
272273
data = self._request("POST", "/v1/vol-surface/bulk", json=body)
273274
return data if raw else BulkVolResponse.model_validate(data)
274275

276+
def vol_surface_raw(
277+
self,
278+
ccy: str,
279+
*,
280+
session: Session = "us",
281+
date: Optional[str] = None,
282+
raw: bool = False,
283+
) -> Union[RawVolSurface, Dict[str, Any]]:
284+
"""Raw market-quoted vol surface for one snapshot (PRO and ULTRA).
285+
286+
Returns every listed expiry with its quoted strike ladder
287+
(``strikes``) and the market implied vol at each strike
288+
(``mkt_vol``, index-aligned), plus ``forward``, ``atm_strike``, and
289+
``spot``. This is the discrete market data *before* model fitting —
290+
for a smooth interpolated vol at an arbitrary strike/moneyness/delta
291+
use :meth:`vol_surface` or :meth:`vol_surface_bulk`.
292+
293+
Parameters
294+
----------
295+
ccy:
296+
Asset symbol.
297+
session:
298+
``"asia"``, ``"london"``, or ``"us"``. Subject to your plan tier.
299+
date:
300+
Optional snapshot date (``YYYY-MM-DD``). Defaults to the latest
301+
available snapshot.
302+
raw:
303+
If True, return the parsed JSON dict instead of a typed model.
304+
305+
Example
306+
-------
307+
308+
surf = cv.vol_surface_raw(ccy="BTC", session="us")
309+
for exp in surf.expiries:
310+
print(exp.expiry, exp.forward, len(exp.strikes), "strikes")
311+
"""
312+
params = _drop_none({
313+
"ccy": ccy,
314+
"session": session,
315+
"date": date,
316+
})
317+
data = self._request("GET", "/v1/vol-surface/raw", params=params)
318+
return data if raw else RawVolSurface.model_validate(data)
319+
275320
def vol_history(
276321
self,
277322
ccy: str = "BTC",

cryptovol/models.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,37 @@ def failed(self) -> List[BulkResultItem]:
151151
return [r for r in self.results if not r.ok]
152152

153153

154+
# ── /v1/vol-surface/raw ───────────────────────────────────────────────────────
155+
156+
157+
class RawSurfaceExpiry(BaseModel):
158+
"""Market-quoted vols for one listed expiry: index-aligned ``strikes``/``mkt_vol``."""
159+
160+
model_config = ConfigDict(extra="allow")
161+
162+
expiry: str
163+
tenor_days: Optional[int] = None
164+
forward: Optional[float] = None
165+
atm_strike: Optional[float] = None
166+
strikes: List[float] = Field(default_factory=list)
167+
mkt_vol: List[float] = Field(default_factory=list)
168+
169+
170+
class RawVolSurface(BaseModel):
171+
"""Response from ``GET /v1/vol-surface/raw`` — raw market-quoted surface
172+
(discrete strike ladders, before model fitting)."""
173+
174+
model_config = ConfigDict(extra="allow")
175+
176+
ccy: str
177+
session: str
178+
datetime: Optional[str] = None
179+
vol_date: str
180+
spot: Optional[float] = None
181+
count: int
182+
expiries: List[RawSurfaceExpiry] = Field(default_factory=list)
183+
184+
154185
# ── /v1/vol-history ───────────────────────────────────────────────────────────
155186

156187

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "cryptovol"
7-
version = "0.3.0"
7+
version = "0.4.0"
88
description = "Python SDK for the CryptoVol API — institutional-grade crypto implied volatility data."
99
readme = "README.md"
1010
requires-python = ">=3.9"

0 commit comments

Comments
 (0)