QuantLib 金融計算——數學工具之求解器

來源:互聯網
上載者:User

標籤:for   als   NPU   方式   區間   art   lib   使用   mdf   

目錄

  • QuantLib 金融計算——數學工具之求解器
    • 概述
      • 調用方式
    • 非 Newton 演算法(不需要導數)
    • Newton 演算法(需要導數)

如果未做特別說明,文中的程式都是 Python3 代碼。

QuantLib 金融計算——數學工具之求解器

載入模組

import QuantLib as qlimport scipyfrom scipy.stats import normprint(ql.__version__)
1.12
概述

QuantLib 提供了多種類型的一維求解器,用以求解單參數函數的根,

\[f(x)=0\]

其中 \(f : R \to R\) 是實數域上的函數。

QuantLib 提供的求解器類型有:

  • Brent
  • Bisection
  • Secant
  • Ridder
  • Newton(要求提供成員函數 derivative,計算導數)
  • FalsePosition

這些求解器的建構函式均為預設建構函式,不接受參數。例如,Brent 求解器執行個體的構造語句為 mySolv = Brent()

調用方式

求解器的成員函數 solve 有兩種調用方式:

solve(f,      accuracy,      guess,      step)solve(f,      accuracy,      guess,      xMin,      xMax)
  • f:單參數函數或函數對象,傳回值為一個浮點數。
  • accuracy:浮點數,表示求解精度 \(\epsilon\),用於停止計算。假設 \(x_i\) 是根的準確解,
    • 當 \(|f(x)| < \epsilon\);
    • 或 \(|x - x_i| < \epsilon\) 時停止計算。
  • guess:浮點數,對根的初始猜測值。
  • step:浮點數,在第一種調用方式中,沒有限定根的區間範圍,演算法需要自己搜尋,確定一個範圍。step 規定了搜尋演算法的步長。
  • xMinxMax:浮點數,左右區間範圍

根求解器在量化金融中最經典的應用是求解隱含波動率。給定期權價格 \(p\) 以及其他參數 \(S_0\)、\(K\)、\(r_d\)、\(r_f\)、\(\tau\),我們要計算波動率 \(\sigma\),滿足

\[f(\sigma) = \mathrm{blackScholesPrice}(S_0 , K, r_d , r_f , \sigma , \tau, \phi) - p = 0\]

其中 Black-Scholes 函數中 \(\phi = 1\) 代表看漲期權;\(\phi = ?1\) 代表看跌期權。

非 Newton 演算法(不需要導數)

下面的例子顯示了如何加一個多參數函數封裝為一個單參數函數,並使用 QuantLib 求解器計算隱含波動率。

例子 1

# Black-Scholes 函數def blackScholesPrice(spot,                      strike,                      rd,                      rf,                      vol,                      tau,                      phi):    domDf = scipy.exp(-rd * tau)    forDf = scipy.exp(-rf * tau)    fwd = spot * forDf / domDf    stdDev = vol * scipy.sqrt(tau)    dp = (scipy.log(fwd / strike) + 0.5 * stdDev * stdDev) / stdDev    dm = (scipy.log(fwd / strike) - 0.5 * stdDev * stdDev) / stdDev    res = phi * domDf * (fwd * norm.cdf(phi * dp) - strike * norm.cdf(phi * dm))    return res# 封裝函數def impliedVolProblem(spot,                      strike,                      rd,                      rf,                      tau,                      phi,                      price):    def inner_func(v):        return blackScholesPrice(spot, strike, rd, rf, v, tau, phi) - price    return inner_funcdef testSolver1():    # setup of market parameters    spot = 100.0    strike = 110.0    rd = 0.002    rf = 0.01    tau = 0.5    phi = 1    vol = 0.1423    # calculate corresponding Black Scholes price    price = blackScholesPrice(spot, strike, rd, rf, vol, tau, phi)    # setup a solver    mySolv1 = ql.Bisection()    mySolv2 = ql.Brent()    mySolv3 = ql.Ridder()    accuracy = 0.00001    guess = 0.25    min = 0.0    max = 1.0    myVolFunc = impliedVolProblem(spot, strike, rd, rf, tau, phi, price)    res1 = mySolv1.solve(myVolFunc, accuracy, guess, min, max)    res2 = mySolv2.solve(myVolFunc, accuracy, guess, min, max)    res3 = mySolv3.solve(myVolFunc, accuracy, guess, min, max)    print(‘{0:<35}{1}‘.format(‘Input Volatility:‘, vol))    print(‘{0:<35}{1}‘.format(‘Implied Volatility Bisection:‘, res1))    print(‘{0:<35}{1}‘.format(‘Implied Volatility Brent:‘, res2))    print(‘{0:<35}{1}‘.format(‘Implied Volatility Ridder:‘, res3))testSolver1()
# Input Volatility:                  0.1423# Implied Volatility Bisection:      0.14229583740234375# Implied Volatility Brent:          0.14230199334812577# Implied Volatility Ridder:         0.1422999996313447
Newton 演算法(需要導數)

Newton 演算法要求為根求解器提供 \(f(\sigma)\) 的導數 \(\frac{\partial f}{\partial \sigma}\)(即 vega)。下面的例子顯示了如何將導數添加進求解隱含波動率的過程。為此我們需要一個類,一方面提供作為一個函數對象,另一方面要提供成員函數 derivative

例子 2

class BlackScholesClass:    def __init__(self,                 spot,                 strike,                 rd,                 rf,                 tau,                 phi,                 price):        self.spot_ = spot        self.strike_ = strike        self.rd_ = rd        self.rf_ = rf        self.phi_ = phi        self.tau_ = tau        self.price_ = price        self.sqrtTau_ = scipy.sqrt(tau)        self.d_ = norm        self.domDf_ = scipy.exp(-self.rd_ * self.tau_)        self.forDf_ = scipy.exp(-self.rf_ * self.tau_)        self.fwd_ = self.spot_ * self.forDf_ / self.domDf_        self.logFwd_ = scipy.log(self.fwd_ / self.strike_)    def blackScholesPrice(self,                          spot,                          strike,                          rd,                          rf,                          vol,                          tau,                          phi):        domDf = scipy.exp(-rd * tau)        forDf = scipy.exp(-rf * tau)        fwd = spot * forDf / domDf        stdDev = vol * scipy.sqrt(tau)        dp = (scipy.log(fwd / strike) + 0.5 * stdDev * stdDev) / stdDev        dm = (scipy.log(fwd / strike) - 0.5 * stdDev * stdDev) / stdDev        res = phi * domDf * (fwd * norm.cdf(phi * dp) - strike * norm.cdf(phi * dm))        return res    def impliedVolProblem(self,                          spot,                          strike,                          rd,                          rf,                          vol,                          tau,                          phi,                          price):        return self.blackScholesPrice(            spot, strike, rd, rf, vol, tau, phi) - price    def __call__(self,                 x):        return self.impliedVolProblem(            self.spot_, self.strike_, self.rd_, self.rf_,            x,            self.tau_, self.phi_, self.price_)    def derivative(self,                   x):        # vega        stdDev = x * self.sqrtTau_        dp = (self.logFwd_ + 0.5 * stdDev * stdDev) / stdDev        return self.spot_ * self.forDf_ * self.d_.pdf(dp) * self.sqrtTau_def testSolver2():    # setup of market parameters    spot = 100.0    strike = 110.0    rd = 0.002    rf = 0.01    tau = 0.5    phi = 1    vol = 0.1423    # calculate corresponding Black Scholes price    price = blackScholesPrice(        spot, strike, rd, rf, vol, tau, phi)    solvProblem = BlackScholesClass(        spot, strike, rd, rf, tau, phi, price)    mySolv = ql.Newton()    accuracy = 0.00001    guess = 0.10    step = 0.001    res = mySolv.solve(        solvProblem, accuracy, guess, step)    print(‘{0:<20}{1}‘.format(‘Input Volatility:‘, vol))    print(‘{0:<20}{1}‘.format(‘Implied Volatility:‘, res))testSolver2()
# Input Volatility:   0.1423# Implied Volatility: 0.14230000000000048

導數的使用明顯提高了精度。

QuantLib 金融計算——數學工具之求解器

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.