QuantLib 金融计算——数学工具之求解器

目录

  • QuantLib 金融计算——数学工具之求解器

    • 概述

      • 调用方式
    • 非 Newton 算法(不需要导数)
    • Newton 算法(需要导数)

如果未做特别说明,文中的程序都是 Python3 代码。

QuantLib 金融计算——数学工具之求解器

载入模块

import QuantLib as ql
import scipy
from scipy.stats import norm

print(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_func

def 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

导数的使用明显提高了精度。

原文地址:https://www.cnblogs.com/xuruilong100/p/9839441.html

时间: 2024-10-10 06:48:38

QuantLib 金融计算——数学工具之求解器的相关文章

QuantLib 金融计算——数学工具之随机数发生器

目录 QuantLib 金融计算--数学工具之随机数发生器 概述 伪随机数 正态分布(伪)随机数 拟随机数 HaltonRsg SobolRsg 两类随机数的收敛性比较 如果未做特别说明,文中的程序都是 Python3 代码. QuantLib 金融计算--数学工具之随机数发生器 载入模块 import QuantLib as ql import scipy print(ql.__version__) 1.12 概述 随机模拟通常从产生均匀分布的随机数开始.假设 \(X \sim U [0, 1

QuantLib 金融计算——随机过程之概述

目录 QuantLib 金融计算--随机过程之概述 框架 用法与接口 如果未做特别说明,文中的程序都是 Python3 代码. QuantLib 金融计算--随机过程之概述 载入模块 import QuantLib as ql print(ql.__version__) 1.12 框架 随机过程是金融工程中的一个核心概念,是沟通理论分析和计算实践的枢纽.quantlib-python 提供了一组成体系的类架构用于描述实际中最常见到的几种随机过程,以 1.12 版本为例: C++ 版本的实现提供了

QuantLib 金融计算——基本组件之 Date 类

QuantLib 金融计算--基本组件之 Date 类 QuantLib 将金融领域的日期对象抽象为 Date 类,并提供了丰富的计算函数.需要注意的是,quantlib-python 中的 Date 类并不同于 python 自身包含的 datetime 类,也没有继承关系. 载入 QuantLib: import QuantLib as ql print(ql.__version__) 1.10 Date 对象的构造 Date 对象的构造方式有两种,分别是 Date(serialNumber

QuantLib 金融计算

QuantLib 金融计算 QauntLib 入门 基本组件之 Date 类 基本组件之 Calendar 类 原文地址:https://www.cnblogs.com/xuruilong100/p/8711520.html

QuantLib 金融计算——基本组件之 InterestRate 类

如果未做特别说明,文中的程序都是 Python3 代码. QuantLib 金融计算--基本组件之 InterestRate 类 围绕收益率展开的若干计算(如计算贴现因子)是固定收益分析中最基础的部分.同时,由于固定收益产品在付息频率.计息方式.天数计算规则等细节方面的多样性,这一块的计算显得更加复杂繁琐.QuantLib 将与收益率有关的计算整合封装在 InterestRate 类,用户所作的只是按照规定配置特定的参数. 载入 QuantLib: import QuantLib as ql p

QuantLib 金融计算——收益率曲线之构建曲线(1)

目录 QuantLib 金融计算--收益率曲线之构建曲线(1) YieldTermStructure DiscountCurve DiscountCurve 对象的构造 ZeroCurve ZeroCurve 对象的构造 如果未做特别说明,文中的程序都是 Python3 代码. QuantLib 金融计算--收益率曲线之构建曲线(1) 理论和实践上有多种方法可以构建与市场一致的收益率曲线,背后的方法论取决于市场上的可获得金融工具的流动性.在构建收益率曲线时有两个选项必须选定好:插值方法和所选的金

QuantLib 金融计算——收益率曲线之构建曲线(2)

目录 QuantLib 金融计算--收益率曲线之构建曲线(2) YieldTermStructure 问题描述 Piecewise** 分段收益率曲线的原理 Piecewise** 对象的构造 FittedBondDiscountCurve FittedBondDiscountCurve 的原理 FittedBondDiscountCurve 的构造 FittingMethod 类 拟合曲线 如果未做特别说明,文中的程序都是 Python3 代码. QuantLib 金融计算--收益率曲线之构建

QuantLib 金融计算——基本组件之 ExchangeRateManager 类

目录 QuantLib 金融计算--基本组件之 ExchangeRateManager 类 概述 Money 类中的汇率转换配置 ExchangeRateManager 函数 如果未做特别说明,文中的程序都是 python3 代码. QuantLib 金融计算--基本组件之 ExchangeRateManager 类 载入 QuantLib: import QuantLib as ql print(ql.__version__) 1.15 概述 QuantLib 中管理货币之间汇率信息的类是 E

QuantLib 金融计算——收益率曲线之构建曲线(4)

目录 QuantLib 金融计算--收益率曲线之构建曲线(4) 概述 三次样条函数与期限结构 knots 的选择 实现三次样条函数 实现拟合方法 测试 参考文献 如果未做特别说明,文中的程序都是 C++11 代码. QuantLib 金融计算--收益率曲线之构建曲线(4) 本文代码对应的 QuantLib 版本是 1.15.相关源代码可以在 QuantLibEx 找到. 概述 QuantLib 中提供了用三次 B 样条函数拟合期限结构的功能,但是,并未提供使用三次样条函数拟合期限结构的功能.本文