You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QuantLib报错Root Not Bracketed:如何调整隐含波动率求解上下界?

欧式香草期权隐含波动率计算的根查找边界问题

我使用以下Python代码计算欧式香草期权的隐含波动率:

import QuantLib as ql

exercise = ql.EuropeanExercise(expiry_date)
ql.Settings.instance().evaluationDate = calculation_date
payoff = ql.PlainVanillaPayoff(ql.Option.Call, strike)
option = ql.VanillaOption(payoff, exercise)
S = ql.QuoteHandle(ql.SimpleQuote(spot))
r = ql.YieldTermStructureHandle(ql.FlatForward(0, calendar, r0, day_count))
q = ql.YieldTermStructureHandle(ql.FlatForward(0, calendar, q0, day_count))
sigma = ql.BlackVolTermStructureHandle(ql.BlackConstantVol(0, calendar, 10, day_count))
process = ql.BlackScholesMertonProcess(S, q, r, sigma)
iv = option.impliedVolatility(option_price, process)

但在部分场景下遇到如下错误:

RuntimeError: root not bracketed: f[1e-07,4] -> [1.017420e-05,1.017420e-05]

该错误表明根查找算法无法在给定的1e-7(下界)和4(上界)范围内找到根,请问应如何调整这些上下界?


解决方案

1. 先验证期权价格的无套利合理性

首先确认输入的option_price符合无套利边界,否则不存在有效隐含波动率:

  • 看涨期权:max(S - K*exp(-r*T), 0) ≤ option_price ≤ S
  • 看跌期权:max(K*exp(-r*T) - S, 0) ≤ option_price ≤ K*exp(-r*T)
    其中T是期权剩余期限(以年为单位),K是行权价,S是标的现价,r是无风险利率。如果价格超出范围,先修正输入值。

2. 显式自定义波动率边界

默认边界(1e-7到4)无法覆盖所有场景,可根据期权特征调整:

  • 下界:将默认的极小值(1e-7)提高到0.001(0.1%),避免数值计算问题;极端情况可设为1e-6,但不建议设为0。
  • 上界:对于长期期权、深度实值/虚值期权,可将上界从4(400%)提高到10(1000%)甚至20(2000%),这类极端波动率在特殊市场环境下是合理的。

修改代码时,在impliedVolatility方法中显式指定边界参数:

# 自定义边界:下界0.001,上界10;同时指定精度和最大迭代次数
iv = option.impliedVolatility(option_price, process, 1e-4, 100, 0.001, 10)

参数说明:

  • 第3个参数:计算精度(如1e-4表示波动率精确到0.01%)
  • 第4个参数:最大迭代次数
  • 第5、6个参数:分别为波动率的下界和上界

3. 动态生成基于初始估算的边界

先估算一个接近真实解的初始波动率,再以此为基准设置边界,能降低根查找失败概率:

  • 平值期权:可用sqrt(2*pi/T)作为初始值(T为剩余期限年数)
  • 实值/虚值期权:结合期权内在价值估算初始波动率,再将边界设为初始值的0.1倍到5倍

示例代码:

# 计算剩余期限(年)
T = (expiry_date - calculation_date).days / 365.0
# 简单估算初始波动率
initial_sigma = min(1.0, max(0.1, option_price / (spot * (T ** 0.5))))
# 动态生成边界
lower_bound = max(0.001, initial_sigma * 0.1)
upper_bound = initial_sigma * 5.0
# 调用隐含波动率计算
iv = option.impliedVolatility(option_price, process, 1e-4, 100, lower_bound, upper_bound)

4. 捕获异常并逐步扩大边界重试

如果仍出现边界问题,可捕获RuntimeError,依次尝试更宽的边界:

def get_implied_vol(option, process, option_price):
    # 定义多组边界,逐步扩大范围
    bound_pairs = [(0.001, 4), (0.001, 10), (0.001, 20), (0.0001, 30)]
    for lower, upper in bound_pairs:
        try:
            return option.impliedVolatility(option_price, process, 1e-4, 100, lower, upper)
        except RuntimeError:
            continue
    # 所有边界尝试失败,返回None或抛出自定义异常
    return None

iv = get_implied_vol(option, process, option_price)

内容的提问来源于stack exchange,提问作者SinaQuant

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 13:07:28