用Python计算分析实现波动率和隐含波动率

今天又敲了一个volatility_pricer.py,可以分别计算给定股票的实现波动率,和用Black-Scholes算出的隐含波动率。
Python代码可以详见:
class VolatilityPricer():
    """
    Realized vol:
    Same as Black-Scholes, we assume the underlying follows a Geometric Brownian Motion.
    Then its log return follows a Normal distribution, with mean as 0.
    We take as input the historical daily underlying prices.
    Annualization factor is 252.
    Degree of Freedom is 0 as we are calculating the exact realized vol for the given historical period.
 
    Implied vol:
    Use Black-Scholes to back out the implied volatility from the given market option price.
 
    """
 
    def __init__(self):
        self.historicalDataBySymbol = dict()
        self.dataHub = DataHub()
        self.realizedVolBySymbol = dict()
 
    def _loadHistoricalUnderlyingData(self, startDate, endDate, symbols):
        self.historicalDataBySymbol = self.dataHub.downloadDataFromYahoo(startDate, endDate, symbols)
 
    def _calculateRealizedVol(self, ts):
        """ Calculate the realized vol from given time series """
        pctChange = ts.pct_change().dropna()
        logReturns = np.log(1+pctChange)
        vol = np.sqrt(np.sum(np.square(logReturns)) / logReturns.size)
        annualizedVol = vol * np.sqrt(252)
 
        return annualizedVol
 
    def getRealizedVol(self, startDate=datetime.date.today()-datetime.timedelta(days=30), endDate=datetime.date.today(), symbols=['SPY']):
        """ Calculate the realized volatility from historical market data """
        self._loadHistoricalUnderlyingData(startDate, endDate, symbols)
 
        for symbol, df in self.historicalDataBySymbol.iteritems():
            # Use daily Close to calculate realized vols
            realizedVol = self._calculateRealizedVol(df.loc[:, 'Close'])
            self.realizedVolBySymbol[symbol] = realizedVol
 
        return self.realizedVolBySymbol
 
    def getImpliedVol(self, optionPrice=17.5, callPut='Call', spot=586.08, strike=585.0, tenor=0.109589, rate=0.0002):
        """ Calculate the implied volatility from option market price """
        return blackScholesSolveImpliedVol(optionPrice, callPut, spot, strike, tenor, rate)

计算股票的实现波动率

这个我们也是假设股票的价格遵循Geometric Browian Motion,进而它的log return就服从Normal Distribution。
我的pricer可以自动从Yahoo Finance抓取历史数据,并以此构建时间序列。这样我们就可以算出股票的log returns序列,进而就可以算出它的方差,最后把波动率年化。
使用方法:
from volatility_pricer import VolatilityPricer
vp = VolatilityPricer()
vp.getRealizedVol()
{'SPY': 0.086197389793546381}
vp.getRealizedVol(startDate=datetime.date(2018,1,1))
{'SPY': 0.16562165494524139}

计算给定期权的隐含波动率

这个原理就很简单了,用Black-Scholes已知期权价格back out波动率。
但是没有公式可以直接进行计算,所以我用了牛顿导数方法来不断求最优解。我们在每一步需要计算一个当前波动率下的期权价格以及对应的Vega,然后不断缩小误差,直到满意的误差范围。
使用方法:
from volatility_pricer import VolatilityPricer
vp = VolatilityPricer()
vp.getImpliedVol()
0.21921387741959775
哈哈,我还是一如既往地太懒写细节,大家就自己看code吧。
如果有问题或者需要交流,欢迎关注和联系我哈。

4 thoughts on “用Python计算分析实现波动率和隐含波动率”

  1. thanks for your sharing. can you tell me the detail of the function :
    def getImpliedVol(self, optionPrice=17.5, callPut=’Call’, spot=586.08, strike=585.0, tenor=0.109589, rate=0.0002) ???
    thanks !!

    1. Sure, the idea is straightforward. Black-Scholes takes 5 input parameters and calculate Option price. So this implied vol function reverse this calculation. That is, it takes the known option price as input, together with the other 4 parameters, to back out the unknown volatility. And such calculated vol is called Implied vol.

      1. thanks for your reply. I have a try, but it will spend much time using my code as follow:
        sigma=0.01
        C=0 ### C denote price using BSM model
        upper=0.008
        lower=0.006
        [S,r,q,T,K,p]=data1.loc[0,[‘S(t)’,’r’,’q’,’DTM’,’X’,’Option Price’]]
        tmp1=S*(math.exp((-1)*q*T))
        tmp2=S/K
        tmp3=(np.log(tmp2)+T*(r-q+(0.5*(sigma**2))))/(sigma*np.sqrt(T))
        tmp4=tmp3-np.sqrt(T)*sigma
        tmp5=norm.cdf(tmp3,0,1)
        tmp6=norm.cdf(tmp4,0,1)
        while abs(C-p)>1e-6:
        C=tmp1*tmp5-K*math.exp((-1)*r*T)*tmp6
        if C-p>0:
        upper=sigma
        sigma=(sigma+lower)/2
        else:
        lower=sigma
        sigma=(sigma+upper)/2
        print(sigma)

        so, do you have better way to solve the problem? thanks!!

Leave a Reply

Your email address will not be published.