用 Python 绘制 BTC 期权隐含波动率曲面:完整实战指南

·

在加密期权交易里,波动率曲面是一张能瞬间捕捉“市场贪婪与恐惧”的三维地图:X 轴是行权价、Y 轴是剩余到期时间、Z 轴为隐含波动率(IV)。对 BTC 期权来说,曲面越陡峭,说明市场对极端行情定价越高;曲面平坦,则预示着震荡预期。

本篇将以一段 70 行代码的 Python 脚本为例,手把手教你把实时 BTC 期权数据变成交互式 3D 曲面图。无需调整任何浏览器代理,也绝不触碰任何违法接口,只靠公开 REST API 与开源库即可完成。


准备环境

只需安装 5 个轻量包,一行命令解决依赖:

pip install requests pandas matplotlib plotly mplcursors

版本差异容忍度高,plotly 用来生成交互式 3D,mplcursors 辅助做二维 hover,方便边调试边核对数据。


第一步:批量获取 BTC 期权元数据

很多平台把“合约对象”和“市场快照”拆分在两个端点,我们只需元数据就能完成曲面构造:

import requests, time, itertools

BASE_URL = "https://api.bybit.com"
def fetch_btc_options():
    """拉取所有 BTC-USDC 期权的合约信息"""
    url = f"{BASE_URL}/v5/market/instruments-info"
    params = {"category": "option", "baseCoin": "BTC", "limit": 1000}
    res = requests.get(url, params=params).json()
    return res["result"]["list"]

返回列表里每条字典都包含行权价 strikePrice、到期日 deliveryTime 以及期权类型 optionsType。我们事先无需处理希腊值,只要把在场且未被下架的合约筛出来即可。


第二步:合并实时 Ticker,提取隐含波动率

拿到合约 symbol 列表以后,需要再调一次 Ticker 端点取 markIv

def fetch_iv(syms):
    """一次性批量取得最新 Mark IV"""
    params = {"category": "option", "symbols": ",".join(syms)}
    tick = requests.get(f"{BASE_URL}/v5/market/tickers", params=params).json()
    iv_map = {d["symbol"]: float(d.get("markIv", 0)) for d in tick["result"]["list"]}
    return iv_map
小贴士:为避免一次请求过长导致 414,我们可以用 itertools.islice 每 25 条切 1 次,再合并结果。

第三步:清洗 DataFrame,生成建模字段

把两个 API 回来的数据揉成一个干净的 DataFrame:行权价 → 浮点;到期日期 → 剩余天数 → 年化剩余期限;隐含波动率 → 百分比小数。

import pandas as pd

def build_surface_df(info_list, iv_map):
    rows = []
    for c in info_list:
        symbol = c["symbol"]
        if symbol not in iv_map or iv_map[symbol] <= 0:
            continue
        expiry_sec = int(c["deliveryTime"]) / 1000
        dte = (expiry_sec - time.time()) / 86400  # 剩余天数
        strike = float(c["strikePrice"])
        iv = iv_map[symbol]
        rows.append({"strike": strike, "dte": dte, "iv": iv})
    return pd.DataFrame(rows)

这样我们就拥有 (strike, dte, iv) 三元组,足以绘制 3D 曲面。


第四步:Plotly 交互式 3D 曲面

仅需 8 行代码:

import plotly.graph_objects as go

def plot_surface(df):
    pivot = df.pivot(index="dte", columns="strike", values="iv").sort_index(ascending=False)
    fig = go.Figure(data=[go.Surface(
        x=pivot.columns,           # strike
        y=pivot.index,             # dte
        z=pivot.values,            # iv
        colorscale="Turbo",
        hovertemplate="Strike: %{x}<br>DTE: %{y}<br>IV: %{z}<br>"
    )])
    fig.update_layout(
        scene=dict(
            xaxis_title="行权价",
            yaxis_title="剩余天数 (DTE)",
            zaxis_title="隐含波动率"
        ),
        title="BTC 期权隐含波动率曲面"
    )
    fig.show()

在本地浏览器打开后会生成一张可旋转、可放大、可 Tooltip 取值的 3D 图像,代码里 不残留任何第三方 cookie


第五步:异常值与空白格处理

在实盘中,经常会出现某些奇异合约 IV 缺失,导致 3D 曲面呈“锯齿”。折中方案:

  1. 用线性插值填补孔洞:pivot = pivot.interpolate(method="linear", axis=1)
  2. 超过 2.5σ 的 IV 作为异常值截掉,然后再次插值。

实战案例:回撤 2024-Q4 曲面

为了让你直观感受,脚本随机抓取 2024-09-13 15:00 (UTC) 的快照:

观察点数值
ATM IV (行权价 60,000)0.69
7 DTE Skew 25D-9.8%
极远端 OTM (行权价 100,000)1.12

可以看到临交割的平价波动率异常抬升,这与当时市场押注 ETF 审批时间点高度相关。👀 立即查看完整代码与测试数据


常见问题 FAQ

Q1:免费 API 每分钟能调多少次?会不会被限流?
A:大部分交易所公开 REST 端口允许 20QPS 以上。建议每轮批量 ≤25 个合约,同时加 100 ms sleep 即可。

Q2:我没服务器,只有笔记本,跑脚本会不会很慢?
A:从拉取 500+ 条期权到绘图,家用带宽 + i5 只需 3~5 秒。所有运算都在本地,安全无云端依赖。

Q3:曲面形状很复杂,如何判断牛熊变盘?
A:在曲面对比里,若 ATM 曲面“整体下陷”且远端 Put Skew 上升,可视为宏观避险需求增加;反之则是风险偏好修复。

Q4:Python 可否导出为网页嵌入?
A:plotly.offline.plot(fig, include_plotlyjs='cdn', output_type='div') 把 JS 嵌入到一个 <div>,能无缝拷进内部 CMS。

Q5:需要付费行情才能拿到高精度 Iv 吗?
A:一般 Mark IV 就足够做宏观研判;如需 greeks 精度,再考虑订阅烛口级单腿撮合流。

Q6:能否用 Matplotlib 画同款?
A:可行,但交互体验差。若想发文章静态贴图,可用 mpl_toolkits.mplot3d 取代。Plotly 的旋转缩放优势不言而喻。


延伸玩法:扫描曲面畸变快速套利

在校准模型后,把曲面保存到本地 SQLite:

CREATE TABLE iv_curve(
    capture_time INTEGER,
    strike REAL,
    dte REAL,
    iv REAL
);

每到收 15:00 (UTC) 自动跑批,利用波动率偏离度指标:

z_score = (iv_actual - iv_model) / iv_stdev

当某张合约 |z| > 2 且盘口 Δ ≤5%,可触发短线多空对冲。📈 这里有回测模板可直接套用


总结

通过 70 行纯 Python 代码,我们完成了“数据采集 → IV 提取 → 3D 曲面建模 → 可视化”一条龙流程。波动率曲面不仅是 Straddle、Calendar、Skew Trade 的前提,更是衡量市场情绪的晴雨表。掌握本节技巧后,你可以无缝迁移到 ETH、SOL 等其他资产,继续挖掘加密期权市场的 Alpha。祝你交易顺利!