Strasmore Research
学习 Matt Connor作者: Matt Connor · 更新于 2026-08-05

隐含波动率如何计算

隐含波动率没有闭式解。了解求解器如何从期权价格迭代反推出波动率,查看 Python 实现,以及不同数据供应商产生不同数值的原因。

隐含波动率通过迭代计算,而不是通过公式直接求得。不存在能够将期权市场价格反推为波动率数值的闭式表达式。因此,求解器会先猜测一个波动率,用 Black-Scholes 模型为期权定价,再将模型价格与市场报价比较。随后不断重复这一过程,直到两者精确到一美分以内。下文将完整介绍这一方法:定价函数、使用 Python 标准库编写的搜索循环,以及不同数据供应商为何会为同一份合约发布不同数值。

为什么隐含波动率没有闭式公式

Black-Scholes模型只能单向计算。输入现货价格、行权价、到期时间、利率和波动率这五项数据,模型就会给出理论价格。这六个变量中,有五个可以观测。波动率无法直接观测。它代表对股票从现在到到期日之间价格波动幅度的假设。

交易者会反向求解。市场价格已经显示在屏幕上,未知数变成了波动率。隐含波动率是使Black-Scholes价格等于期权市场价格的波动率输入值。波动率项用希腊字母Sigma表示,分别出现在d1和d2的正态分布函数中,而且各出现一次。无法通过代数变形将其单独移到等式一侧。代数推导到此为止。接下来要进行数值搜索。隐含波动率衡量什么介绍其含义;本页介绍求解过程。

模型的两个特性使搜索过程相对简单。看涨期权的模型价格会随着波动率上升而上升,没有例外,而且变化平滑。对于一个只会单调上升的量,可以通过不断缩小区间来锁定其数值。

求解器按每份合约运行一次

输出结果是每份合约一个数值,而不是每只股票一个数值。同一股票、同一到期窗口内的合约,结果也可能彼此不同。以下是2026年6月30日成交、剩余20至45天到期的所有苹果公司(AAPL)期权,并按行权价占股价的比例分组:

查询每份合约一次求解:AAPL 按行权价区间划分的隐含波动率,2026年6月30日
每个数字背后的完整 SQL
WITH toFloat64(strike_price) / toFloat64(underlying_close) AS moneyness
SELECT multiIf(moneyness < 0.90, '0.80-0.90',
               moneyness < 0.95, '0.90-0.95',
               moneyness < 1.00, '0.95-1.00',
               moneyness < 1.05, '1.00-1.05',
               moneyness < 1.10, '1.05-1.10',
                                 '1.10-1.20') AS strike_vs_spot,
       round(100 * avg(toFloat64(implied_volatility)), 1) AS implied_vol_pct,
       count() AS contract_count
FROM global_markets.options_greeks
WHERE underlying_symbol = 'AAPL'
  AND date = toDate('2026-06-30')
  AND days_to_expiry BETWEEN 20 AND 45
  AND iv_converged = 1
  AND volume > 0
  AND moneyness BETWEEN 0.80 AND 1.20
GROUP BY strike_vs_spot
ORDER BY min(moneyness)
Run this yourself

沿着行权价阶梯观察,0.80-0.90区间的求解结果为35.5%,0.95-1.00区间的结果为28.1%,1.10-1.20区间的结果为27.3%。一家公司、一个交易日、6个结果。这条曲线的弯曲部分有一个名称,即波动率偏斜;用每只股票一个波动率无法描绘这条曲线。

求解器需要匹配的 Black-Scholes 价格

S 是股价,K 是行权价,T 是距离到期的年数,r 是无风险利率,N() 是标准正态累积分布函数,即标准正态随机变量取值低于给定点的概率。Python 在 math.erf 中提供了这一功能,因此只需使用解释器即可。

apt-get update && apt-get install -y python3

如果您在非 root 权限的计算机上操作,请在两条命令前都加上 sudo。然后将以下内容保存为 iv.py

import math

def norm_cdf(x):
    return 0.5 * (1.0 + math.erf(x / math.sqrt(2.0)))

def bs_call(S, K, T, r, sigma):
    if T <= 0.0 or sigma <= 0.0:
        return max(S - K, 0.0)
    d1 = (math.log(S / K) + (r + 0.5 * sigma * sigma) * T) / (sigma * math.sqrt(T))
    d2 = d1 - sigma * math.sqrt(T)
    return S * norm_cdf(d1) - K * math.exp(-r * T) * norm_cdf(d2)

这就是完整的正向模型。输入波动率,即可得到价格。

隐含波动率的计算方法:分步说明

二分法是首先应掌握的方法。它不会发散,也不需要微积分。

  1. 将答案限定在0.01(年化1%)和5.0(年化500%)之间。所有有交易的期权都处于这一范围内。
  2. 使用区间中点为期权定价。
  3. 如果模型价格高于市场报价,说明猜测值过高:将区间上限下调至中点。如果模型价格低于市场报价,则将区间下限上调至中点。
  4. 当模型价格与市场报价的差距小于一美分时停止。
def implied_vol(price, S, K, T, r, lo=0.01, hi=5.0, tol=0.01):
    for _ in range(100):
        mid = 0.5 * (lo + hi)
        diff = bs_call(S, K, T, r, mid) - price
        if abs(diff) < tol:
            return mid
        if diff > 0.0:
            hi = mid
        else:
            lo = mid
    return 0.5 * (lo + hi)

# $100 stock, $100 strike, three months, 4% rates, $5.00 on the screen
print(round(implied_vol(5.00, 100.0, 100.0, 0.25, 0.04), 4))

运行 python3 iv.py。输出约为0.226,表示在这一假设报价下,隐含波动率约为年化22.6%。每次迭代都会将区间缩小一半。宽度为4.99的区间缩小二十次后,宽度会小于0.00001,因此100次迭代的上限不会成为限制。

为什么牛顿—拉夫森法收敛更快,以及它在哪些情况下会失效

二分法舍弃了模型已经提供的信息。Vega表示波动率每变动一个单位,期权价格的变化量,Black-Scholes模型可以用闭式公式计算该数值。牛顿—拉夫森法将其视为斜率:先测量定价误差,再除以Vega,并据此调整猜测值。

def bs_vega(S, K, T, r, sigma):
    d1 = (math.log(S / K) + (r + 0.5 * sigma * sigma) * T) / (sigma * math.sqrt(T))
    return S * math.sqrt(T) * math.exp(-0.5 * d1 * d1) / math.sqrt(2.0 * math.pi)

def implied_vol_newton(price, S, K, T, r, sigma=0.5):
    for _ in range(20):
        v = bs_vega(S, K, T, r, sigma)
        if v < 1e-8:
            return None          # 斜率已接近于零,将任务交还给二分法
        step = (bs_call(S, K, T, r, sigma) - price) / v
        sigma -= step
        if sigma <= 0.0:
            return None          # 步长过大,结果进入无意义区间
        if abs(step) < 1e-6:
            return sigma
    return None

在平值附近,牛顿—拉夫森法通常三到四次迭代即可收敛,而二分法需要十几次。失效原因在于分母:行权价偏离股价越远,Vega越小。以下是同一组AAPL合约,各区域的平均Vega占平值Vega的比例:

查询牛顿步长失灵处:AAPL 按行权价区间划分的 Vega,2026年6月30日
每个数字背后的完整 SQL
WITH toFloat64(strike_price) / toFloat64(underlying_close) AS moneyness,
     (
         SELECT avg(toFloat64(vega))
         FROM global_markets.options_greeks
         WHERE underlying_symbol = 'AAPL'
           AND date = toDate('2026-06-30')
           AND days_to_expiry BETWEEN 20 AND 45
           AND iv_converged = 1
           AND volume > 0
           AND abs(toFloat64(strike_price) / toFloat64(underlying_close) - 1) < 0.025
     ) AS atm_vega
SELECT multiIf(moneyness < 0.90, '0.80-0.90',
               moneyness < 0.95, '0.90-0.95',
               moneyness < 1.00, '0.95-1.00',
               moneyness < 1.05, '1.00-1.05',
               moneyness < 1.10, '1.05-1.10',
                                 '1.10-1.20') AS strike_vs_spot,
       round(100 * avg(toFloat64(vega)) / atm_vega, 1) AS vega_pct_of_atm,
       count() AS contract_count
FROM global_markets.options_greeks
WHERE underlying_symbol = 'AAPL'
  AND date = toDate('2026-06-30')
  AND days_to_expiry BETWEEN 20 AND 45
  AND iv_converged = 1
  AND volume > 0
  AND moneyness BETWEEN 0.80 AND 1.20
GROUP BY strike_vs_spot
ORDER BY min(moneyness)
Run this yourself

虚值和深度实值区域的敏感度仅为平值区域的一小部分:在0.80-0.90区域为平值Vega的33.1%,在1.10-1.20区域为31.6%。用如此小的数去除定价误差,会产生极大的步长,可能使猜测值跌破零;在该区域,模型无法提供有效结果。生产环境中的求解器通常结合使用这两种方法:先用区间确定根,再用牛顿法进行精细调整。Vega介绍了这一希腊字母指标本身。

为什么两个来源报告的隐含波动率不同

模型是公开的,计算方法也已确定,因此分歧只能来自输入数据。

  • 中间价与最新成交价。 求解器需要一个价格。某合约的买价为 $2.00、卖价为 $2.20时,中间价是 $2.10;但最新成交价可能是九十分钟前的 $2.02。对这类合约而言,十美分的价格差异所对应的影响,可能大于一个百分点的波动率差异。
  • 股息与持有成本。 上述函数计算的是不支付股息股票的欧式看涨期权价格。若到期前支付股息,远期价格会下降;不同交易台采用的调整方法和利率也各不相同。
  • 美式期权的提前行权。 美国单只股票期权可以在任何交易日行权,这项权利具有价值,但欧式公式无法纳入。忽略提前行权的求解器会将这部分差异归入波动率。二叉树模型则会直接为行权权利定价。
  • 过时的报价。 某个行权价的期权最后一次成交可能是在周二,但市场上仍显示报价;求解器会将收到的报价直接视为真实数据。

收敛情况会使后两个问题显现出来。下表选取了 2026 年 6 月 30 日的八只知名股票,统计剩余 20 至 45 天到期的成交合约,并同时报告平值波动率以及成功收敛的合约占比:

查询平值隐含波动率与求解器收敛性,8只标的,2026年6月30日
每个数字背后的完整 SQL
WITH abs(toFloat64(strike_price) / toFloat64(underlying_close) - 1) AS distance_from_spot
SELECT underlying_symbol AS symbol,
       round(100 * avgIf(toFloat64(implied_volatility), iv_converged = 1 AND distance_from_spot < 0.05), 1) AS atm_iv_pct,
       round(100 * countIf(iv_converged = 1) / count(), 1) AS solved_pct,
       count() AS contract_count
FROM global_markets.options_greeks
WHERE date = toDate('2026-06-30')
  AND underlying_symbol IN ('AAPL', 'MSFT', 'NVDA', 'AMZN', 'TSLA', 'SPY', 'KO', 'JNJ')
  AND days_to_expiry BETWEEN 20 AND 45
  AND volume > 0
GROUP BY symbol
HAVING countIf(iv_converged = 1 AND distance_from_spot < 0.05) > 0
ORDER BY atm_iv_pct DESC
Run this yourself

47.7% 的 8 个名称中,TSLA 的平值波动率最高;位于最低位的 SPY14.4%。在 TSLA 期权链中,97.8% 的成交合约得出了收敛结果。其余合约的行权价对应价格超出了任何波动率都无法重现的范围,可能是报价低于内在价值,也可能是市场出现交叉报价。类似数值是否算高,是另一个问题:30%的隐含波动率算高吗对此进行了讨论,而预期波动幅度则将其换算成美元区间。

同一合约,每个交易日重新求解

隐含波动率不会被存储。系统会根据屏幕上显示的价格重新计算。下面列出的是到期日为2026年7月17日、交易最活跃的AAPL合约,并跟踪其从6月1日到到期日的变化。行权价和到期日均未改变:

查询一份 AAPL 合约:每个交易日重新求解至2026年7月17日到期
每个数字背后的完整 SQL
WITH (
         SELECT ticker
         FROM global_markets.options_greeks
         WHERE underlying_symbol = 'AAPL'
           AND date = toDate('2026-06-30')
           AND expiration_date = toDate('2026-07-17')
           AND iv_converged = 1
           AND volume > 0
         ORDER BY volume DESC
         LIMIT 1
     ) AS pinned_contract
SELECT date,
       round(100 * avg(toFloat64(implied_volatility)), 1) AS implied_vol_pct,
       round(avg(days_to_expiry)) AS days_to_expiry
FROM global_markets.options_greeks
WHERE ticker = pinned_contract
  AND date BETWEEN toDate('2026-06-01') AND toDate('2026-07-17')
  AND iv_converged = 1
  AND volume > 0
GROUP BY date
ORDER BY date
Run this yourself

29个交易日中,求解得到的数值从25.1%开盘,当时距离到期还有46天;最终收于26.6%,剩余4天。该曲线上的每个点,都是针对当日报价运行上述循环后得到的一次结果。我们在每个ticker页面发布相同的计算结果:AAPL隐含波动率每日对完整期权链运行该计算,因此读者可以使用本页代码复现其中的任一数值。

隐含波动率计算常见问题

隐含波动率有计算公式吗?

没有。Black-Scholes模型可以根据波动率计算期权价格,但这个映射没有初等逆函数,因为sigma在正态分布函数中出现了两次。您在这里或其他地方看到的每个隐含波动率数值,都是通过迭代求解器计算得出的。

计算需要迭代多少次?

每次二分迭代都会将区间缩小一半。因此,0.01到5.0的区间经过20次迭代后会缩小到0.00001以下;若要将结果匹配到报价的最近一美分,通常需要大约十几次迭代。接近平值时,Newton-Raphson方法通常三到四次即可收敛,但在vega较小时,迭代步长可能不稳定。

为什么我的经纪商和数据供应商显示的隐含波动率不同?

因为它们向求解器输入了不同的数据。常见差异包括中间价与最后成交价的区别、利率和股息假设不同,以及模型是否处理美式期权的提前行权。在成交清淡的行权价上,仅一笔过时的报价就可能使结果相差几个百分点。

同一行权价的看涨期权和看跌期权会得到相同的隐含波动率吗?

理论上会。看跌-看涨平价关系将相同行权价和到期日的两者联系起来。实际中,两种期权的报价由市场分别形成,计算出的数值会有小幅差异。这也是不同供应商的整条期权链平均值不一致的原因之一。

没有市场数据时,我可以计算隐含波动率吗?

可以,但只能针对假设报价。上面的代码允许您手动输入期权价格、行权价、现货价格、到期时间和利率。要匹配实时供应商的数据则更困难,因为您必须使用供应商采用的同一组输入。


这里的每个面板都保存了背后的SQL查询。打开其中一个面板,然后在Strasmore终端上对实时期权链运行相同的求解程序。

#implied volatility#期权#black-scholes#python#how-to