目錄python
若是未作特別說明,文中的程序都是 Python3 代碼。算法
載入模塊app
import QuantLib as ql import pandas as pd import numpy as np import seaborn as sn print(ql.__version__)
1.12
著名的 Heston 模型描述了下列 SDE:ide
\[ \begin{aligned} d S_t & = \mu S_t d t + \sqrt { V_t } S_t d W_t^S \\ d V_t & = \kappa \left( \theta - V_t \right) d t + \sigma \sqrt { V_t } d W_t^V \\ d W_t^S d W_t^V & = \rho d t \end{aligned} \]函數
quantlib-python 中 Heston 過程的構造函數以下:spa
HestonProcess(riskFreeRate, dividendYield, s0, v0, kappa, theta, sigma, rho)
其中,code
riskFreeRate
:YieldTermStructureHandle
對象,描述無風險利率的期限結構;dividendYield
:YieldTermStructureHandle
對象,描述股息率的期限結構;s0
:QuoteHandle
對象,資產價格的起始值;v0
:浮點數,波動率的起始值;kappa
、theta
、sigma
:浮點數,描述波動率的 SDE 的參數;rho
:浮點數,模型中兩個布朗運動之間的相關性除了一些檢查器以外,HestonProcess
沒有提過其餘特別的成員函數。component
因爲方程沒有顯式解,所以必須在 evolve
函數中使用算法進行離散化。quantlib-python 默認的離散化方法是 Quadratic Exponential Martingale 方法(或稱 Quadratic Exponential 方法),具體的算法細節請查看參考文獻(Andersen 和 Leif,2008)orm
因爲 evolve
函數將離散化計算中對布朗運動的離散化以參數形式暴露了出來,使得用戶能夠容易地顯現出隨機波動率對資產價格序列的影響。下面的例子比較了通常 Black Scholes 過程和 Heston 過程,所模擬的資產價格除了波動率結構之外,都徹底一致。對象
def testingStochasticProcesses2(seed): refDate = ql.Date(27, ql.January, 2019) riskFreeRate = 0.0321 dividendRate = 0.0128 spot = 52.0 cal = ql.China() dc = ql.ActualActual() rdHandle = ql.YieldTermStructureHandle( ql.FlatForward(refDate, riskFreeRate, dc)) rqHandle = ql.YieldTermStructureHandle( ql.FlatForward(refDate, dividendRate, dc)) spotHandle = ql.QuoteHandle( ql.SimpleQuote(spot)) kappa = 1.2 theta = 0.08 sigma = 0.05 rho = -0.6 v0 = theta hestonProcess = ql.HestonProcess( rdHandle, rqHandle, spotHandle, v0, kappa, theta, sigma, rho) volHandle = ql.BlackVolTermStructureHandle( ql.BlackConstantVol(refDate, cal, np.sqrt(v0), dc)) bsmProcess = ql.BlackScholesMertonProcess( spotHandle, rqHandle, rdHandle, volHandle) unifMt = ql.MersenneTwisterUniformRng(seed) bmGauss = ql.BoxMullerMersenneTwisterGaussianRng(unifMt) dt = 0.004 numVals = 250 dw = ql.Array(2) x = ql.Array(2) x[0] = spotHandle.value() x[1] = v0 y = x[0] htn = pd.DataFrame( dict( t=np.linspace(0, dt * numVals, numVals + 1), price=np.nan, vol=np.nan)) bsm = pd.DataFrame( dict( t=np.linspace(0, dt * numVals, numVals + 1), price=np.nan, vol=v0)) htn.loc[0, 'price'] = x[0] htn.loc[0, 'vol'] = x[1] bsm.loc[0, 'price'] = y for j in range(1, numVals + 1): dw[0] = bmGauss.next().value() dw[1] = bmGauss.next().value() x = hestonProcess.evolve(htn.loc[j, 't'], x, dt, dw) y = bsmProcess.evolve(bsm.loc[j, 't'], y, dt, dw[0]) htn.loc[j, 'price'] = x[0] htn.loc[j, 'vol'] = x[1] bsm.loc[j, 'price'] = y htn = htn.melt( id_vars='t', var_name='component', value_name='path') htn['type'] = 'stochastic vol' bsm = bsm.melt( id_vars='t', var_name='component', value_name='path') bsm['type'] = 'constant vol' htn_bsm = pd.concat([htn, bsm]) sn.relplot( x='t', y='path', data=htn_bsm, col='component', hue='type', kind="line", height=8, facet_kws=dict(sharey=False)) testingStochasticProcesses2(100)