隐含波动率计算器是错误的

时间:2015-05-20 21:37:15

标签: python finance

我是一名计算机科学家,试图更多地了解量化金融。我有一个计算Black-Scholes模型中欧式看涨期权价值的程序,我正在尝试添加一种计算隐含波动率的方法。

import math
import numpy as np
import pdb
from scipy.stats import norm

class BlackScholes(object):
  '''Class wrapper for methods.'''

  def __init__(self, s, k, t, r, sigma):
    '''Initialize a model with the given parameters.
       @param s: initial stock price
       @param k: strike price
       @param t: time to maturity (in years)
       @param r: Constant, riskless short rate (1 equals 100%)
       @param sigma: Guess for volatility. (1 equals 100%)
    '''
    self.s = s
    self.k = k
    self.t = t
    self.r = r
    self.sigma = sigma
    self.d = self.factors()

  def euro_call(self):
    ''' Calculate the value of a European call option
        using Black-Scholes. No dividends.
        @return: The value for an option with the given parameters.'''
    return norm.cdf(self.d[0]) * self.s - (norm.cdf(self.d[1]) * self.k *
                                     np.exp(-self.r * self.t))

  def factors(self):
    '''
      Calculates the d1 and d2 factors used in a large
      number of Black Scholes equations.
    '''
    d1 = (1.0 / (self.sigma * np.sqrt(self.t)) * (math.log(self.s / self.k)
                    + (self.r + self.sigma ** 2 / 2) * self.t))
    d2 = (1.0 / (self.sigma * np.sqrt(self.t)) * (math.log(self.s / self.k)
                    + (self.r - self.sigma ** 2 / 2) * self.t))
    if math.isnan(d1):
      pdb.set_trace()
    assert(not math.isnan(d1))
    assert(not math.isnan(d2))
    return (d1, d2) 

  def imp_vol(self, C0):
    ''' Calculate the implied volatility of a call option,
        where sigma is interpretered as a best guess.
        Updates sigma as a side effect.
        @rtype: float
        @return: Implied volatility.'''
    for i in range(128):
      self.sigma -= (self.euro_call() - C0) / self.vega()
      assert(self.sigma != -float("inf"))
      assert(self.sigma != float("inf"))
      self.d = self.factors()
    print(C0,
      BlackScholes(self.s, self.k, self.t, self.r, self.sigma).euro_call())
    return self.sigma

  def vega(self):
    ''' Returns vega, which is the derivative of the
        option value with respect to the asset's volatility.
        It is the same for both calls and puts.
        @rtype: float
        @return: vega'''
    v = self.s * norm.pdf(self.d[0]) * np.sqrt(self.t)
    assert(not math.isnan(v))
    return v

以下是我目前的两个测试用例:

print(BlackScholes(17.6639, 1.0, 1.0, .01, 2.0).imp_vol(16.85))
print(BlackScholes(17.6639, 1.0, .049, .01, 2.0).imp_vol(16.85))

最高的一个打印出1.94,这相当接近http://www.option-price.com/implied-volatility.php给出的195.21%的值。然而,底部的一个(如果你删除断言语句)打印出' nan'和以下警告信息。使用断言语句,self.vega()在imp_vol方法中返回零,然后在assert(self.sigma != -float("inf"))中返回。

so.py:51: RuntimeWarning: divide by zero encountered in double_scalars
  self.sigma -= (self.euro_call() - C0) / self.vega()
so.py:37: RuntimeWarning: invalid value encountered in double_scalars
  + (self.r + self.sigma ** 2 / 2) * self.t))
so.py:39: RuntimeWarning: invalid value encountered in double_scalars
  + (self.r - self.sigma ** 2 / 2) * self.t))

2 个答案:

答案 0 :(得分:0)

您在做什么并没有多大意义。您正试图撤消大量短期期权的隐含波动。此选项上的vega有效为0,因此您得到的隐含卷号将毫无意义。浮点舍入为您提供了无限的音量,这一点也不足为奇。

答案 1 :(得分:0)

如果你使用 vega 来估计隐含波动率,你可能正在做一些牛顿梯度搜索的变体,它不会在所有情况下收敛到一个解决方案,我用 R 或 VBA 编程,所以只能提供一个解决方案你来翻译一下,二分搜索方法简单稳健并且总是收敛,从写完整的期权定价模型书的人这里是 Espen Haugs 算法,用于二分搜索以找到隐含波动率;

Newton-Raphson 方法需要部分知识 关于波动率的期权定价公式的衍生 (vega) 在搜索隐含波动率时。对于某些选项 (特别是异国情调和美式期权),vega 不为人所知 裂解性地。二分法是一种更简单的估计方法 vega 未知时的隐含波动率。二分法 需要两个初始波动率估计值(种子值):

  1. 隐含波动率的“低”估计值 al,对应于 一个选项值,CL
  2. “高”波动率估计值 aH,对应于期权 值,CH 期权市场价格 Cm 介于 CL 和 cH 之间。平分- 重估估计作为两者之间的线性插值给出 估计: 如果 c(cr, + ) < c m ,则将 al 替换为 0 i+1 ,否则将 aH 替换为 i+ 1 如果 C(7,+) > cm 直到 lcm — c(cri+i)i < E,此时 cr, ±1 是隐含的 波动率和 E 是所需的准确度。 计算机算法 此函数返回欧洲平原的隐含波动率 香草看涨期权或看跌期权。通过小的修改,该功能可以 也可用于寻找美国和异国情调的隐含波动率 选项。变量计数器跟踪有多少循环 已经完成。如果在 100 次循环内未找到指定准确度 E 的隐含波动率,则算法停止并返回“NA”(不是 可用)。
      Function  GBlackScholesImpVolBisection(CallPutFlag 
       As String, S As Double,
       X As Double, T As Double, r As Double, _
       b As Double, cm As Double) As Variant
       Dim vLow As Double, vHigh As Double, vi As Double
       Dim cLow As Double, cHigh As Double, epsilon As 
   Double
   Dim counter As Integer
   vLow = 0.005
   vHigh = 4
   epsilon = le-08
   cLow = GBlackScholes ( CallPutFlag , S, X, T, r, b, vLow)
   cHigh = GBlackScholes ( CallPutFlag , S, X, T, r, b, vHigh)
   counter = 0
   vi = vLow + (cm — cLow ) * (vHigh — vLow) / ( cHigh — cLow)
   While Abs(cm — GBlackScholes ( CallPutFlag , S, X, T, r, b, vi )) > epsilon
   counter = counter + 1
   If counter = 100 Then
   GBlackScholesImpVolBisection
   Exit Function
   End If
   If GBlackScholes ( CallPutFlag , S, X, T, r, b, vi ) < cm Then
   vLow = vi
   Else
   vHigh = vi
   End If
   cLow = GBlackScholes ( CallPutFlag , S, X, T, r, b, vLow)
   cHigh = GBlackScholes ( CallPutFlag , S, X, T, r, b, vHigh )
   vi = vLow + (cm — cLow ) * (vHigh — vLow) / ( cHigh — cLow)
   Wend
   GBlackScholesImpVolBisection = vi
   End Function```