BLS 隐含波动率

BLS 隐含波动率 由期权市场价格反推隐含波动率
根据标的资产价格、行权价、无风险利率、到期时间与期权市场价值,使用布莱克-斯科尔斯模型计算隐含波动率。默认按看涨期权计算。
计算结果
点击「计算」查看输出
code 计算逻辑代码
以下为「ISDA国际通用」BLS 隐含波动率的 Python 代码示例(基于 QuantLib)。

# 依赖版本:
# python==3.9
# QuantLib==1.43
import math
import traceback
import QuantLib as ql


def qjquant_calu_blsimpv(
    price: float,
    strike: float,
    rate: float,
    time: float,
    value: float,
    option_class: int = 1,          # 1=Call, 0=Put
    limit: float = 10.0,            # 搜索上界
    yield_rate: float = 0.0,        # 标的资产连续复利收益率
    tolerance: float = 1e-6,        # 终止容差
):
    try:
        # ---------- 参数校验 ----------
        if price <= 0 or strike <= 0:
            return {"ok": False, "msg": "标的价格与行权价必须大于 0"}
        if rate < 0:
            return {"ok": False, "msg": "无风险利率不能为负"}
        if time <= 0:
            return {"ok": False, "msg": "到期时间必须大于 0"}
        if value <= 0:
            return {"ok": False, "msg": "期权市场价值必须大于 0"}
        if limit <= 0:
            return {"ok": False, "msg": "搜索上界必须大于 0"}
        if tolerance <= 0:
            return {"ok": False, "msg": "终止容差必须大于 0"}

        # ---------- 构建 QuantLib 对象 ----------
        # 用当前日期作为估值日,到期日 = 估值日 + Time 年
        today = ql.Date.todaysDate()
        ql.Settings.instance().evaluationDate = today

        # 用 Time 年直接构造到期日,确保 dayCount/365 尽可能接近 Time
        expiry_days = max(1, int(round(time * 365)))
        expiry_date = today + ql.Period(expiry_days, ql.Days)

        # 期权类型
        opt_type = ql.Option.Call if option_class == 1 else ql.Option.Put

        # 行权价与收益结构
        payoff = ql.PlainVanillaPayoff(opt_type, strike)
        exercise = ql.EuropeanExercise(expiry_date)
        option = ql.VanillaOption(payoff, exercise)

        # 标的资产价格
        spot = ql.QuoteHandle(ql.SimpleQuote(price))

        # 无风险利率曲线(平坦)
        day_count = ql.Actual365Fixed()
        risk_free_curve = ql.YieldTermStructureHandle(
            ql.FlatForward(today, rate, day_count)
        )

        # 标的资产收益率曲线(平坦)
        dividend_curve = ql.YieldTermStructureHandle(
            ql.FlatForward(today, yield_rate, day_count)
        )

        # 波动率结构:impliedVolatility 本身不需要真实波动率,
        # 但 process 需要一个初始值,此处给一个占位值
        vol_ts = ql.BlackVolTermStructureHandle(
            ql.BlackConstantVol(today, ql.NullCalendar(), 0.20, day_count)
        )

        # Black-Scholes-Merton 过程
        process = ql.BlackScholesMertonProcess(
            spot, dividend_curve, risk_free_curve, vol_ts
        )

        # ---------- 反解隐含波动率 ----------
        # 注意:QuantLib Python SWIG 接口的关键字参数支持不完整,
        # 必须按位置传参:impliedVolatility(price, process, accuracy, maxEvaluations, minVol, maxVol)
        implied_vol = option.impliedVolatility(
            value,                # 目标期权价格
            process,              # BSM 过程
            tolerance,            # accuracy
            2000,                 # maxEvaluations(放宽以提升收敛概率)
            1e-7,                 # minVol
            limit                 # maxVol(搜索上界)
        )

        if implied_vol <= 0 or not math.isfinite(implied_vol):
            return {"ok": False, "msg": "隐含波动率求解失败,请检查输入参数是否合理"}

        return {
            "ok": True,
            "volatility": round(implied_vol, 4),
        }

    except RuntimeError as re:
        # QuantLib 根搜索失败时抛 RuntimeError
        traceback.print_exc()
        return {"ok": False, "msg": f"隐含波动率求解失败(根搜索未收敛): {re}"}
    except ValueError as ve:
        traceback.print_exc()
        return {"ok": False, "msg": f"参数错误: {ve}"}
    except Exception as e:
        traceback.print_exc()
        return {"ok": False, "msg": f"未知错误: {e}"}


# ============================================================
# 示例:复制本文件后直接运行
# ============================================================
if __name__ == "__main__":
    print("=" * 60)
    print("示例 1:看涨期权隐含波动率(平值附近)")
    print("=" * 60)
    r1 = qjquant_calu_blsimpv(
        price=100.0,
        strike=100.0,
        rate=0.05,
        time=1.0,
        value=10.0,
        option_class=1,
    )
    print(r1)

    print()
    print("=" * 60)
    print("示例 2:看跌期权隐含波动率(含标的收益率)")
    print("=" * 60)
    r2 = qjquant_calu_blsimpv(
        price=100.0,
        strike=95.0,
        rate=0.03,
        time=0.5,
        value=8.0,
        option_class=0,
        yield_rate=0.02,
    )
    print(r2)

    print()
    print("=" * 60)
    print("示例 3:看涨期权(高波动、长到期)")
    print("=" * 60)
    r3 = qjquant_calu_blsimpv(
        price=120.0,
        strike=80.0,
        rate=0.04,
        time=2.0,
        value=45.0,
        option_class=1,
        limit=5.0,
        yield_rate=0.01,
    )
    print(r3)

    print()
    print("=" * 60)
    print("示例 4:看跌期权(低波动、短到期)")
    print("=" * 60)
    r4 = qjquant_calu_blsimpv(
        price=100.0,
        strike=120.0,
        rate=0.02,
        time=0.25,
        value=22.0,
        option_class=0,
        tolerance=1e-8,
    )
    print(r4)