簡體   English   中英

隱含波動率計算器錯誤

[英]Implied volatility calculator is wrong

我是一名計算機科學家,正在嘗試更多地了解量化金融。 我有一個用於計算 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' 和以下警告消息。 使用 assert 語句, 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))

你正在做的事情沒有多大意義。 您正試圖收回大量資金、短期期權的隱含波動率。 此選項上的 vega 將有效地為 0,因此您獲得的隱含 vol 數將毫無意義。 浮點舍入給了你無限的體積,我一點也不感到驚訝。

如果您使用 vega 來估計隱含波動率,您可能正在執行牛頓梯度搜索的一些變體,它不會在所有情況下收斂到解決方案,我在 R 或 VBA 中編程,因此只能為您提供一個解決方案來翻譯,二分搜索方法簡單穩健且始終收斂,來自撰寫完整的期權定價模型書籍的人是 Espen Haugs 算法,用於二分搜索以找到隱含波動率;

在搜索隱含波動率時,Newton-Raphson 方法需要了解期權定價公式相對於波動率 (vega) 的偏導數。 對於某些期權(特別是異國期權和美式期權),vega 是未知的。 當 vega 未知時,二分法是一種更簡單的估計隱含波動率的方法。 二分法需要兩個初始波動率估計值(種子值):

  1. 隱含波動率 al 的“低”估計值,對應於期權價值 CL
  2. “高”波動率估計 aH 對應於期權價值 CH 期權市場價格 Cm 介於 CL 和 cH 之間。 等分估計作為兩個估計之間的線性插值給出:如果 c(cr, + ) < cm 用 0 i+1 替換 al,否則如果 C(7,+ ) > cm 用 i+1 替換 aH直到 lcm — c(cri+i)i < E,此時 cr,±1 是隱含波動率,E 是所需的准確度。 計算機算法 此函數返回歐洲普通看漲期權或看跌期權的隱含波動率。 稍加修改,該函數還可用於計算美式期權和奇異期權的隱含波動率。 變量 counter 跟蹤已完成的循環次數。 如果在 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```

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM