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)