如果未做特别说明,文中的程序都是 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

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

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

  1. QuantLib 金融计算——数学工具之优化器

    目录 QuantLib 金融计算--数学工具之优化器 概述 Optimizer Constraint OptimizationMethod EndCriteria 示例 Rosenbrock 问题 校 ...

  2. QuantLib 金融计算——数学工具之数值积分

    目录 QuantLib 金融计算--数学工具之数值积分 概述 常见积分方法 高斯积分 如果未做特别说明,文中的程序都是 Python3 代码. QuantLib 金融计算--数学工具之数值积分 载入模 ...

  3. QuantLib 金融计算——数学工具之插值

    目录 QuantLib 金融计算--数学工具之插值 概述 一维插值方法 二维插值方法 如果未做特别说明,文中的程序都是 Python3 代码. QuantLib 金融计算--数学工具之插值 载入模块 ...

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

    目录 QuantLib 金融计算--数学工具之随机数发生器 概述 伪随机数 正态分布(伪)随机数 拟随机数 HaltonRsg SobolRsg 两类随机数的收敛性比较 如果未做特别说明,文中的程序都 ...

  5. QuantLib 金融计算

    我的微信:xuruilong100 <Implementing QuantLib>译后记 QuantLib 金融计算 QuantLib 入门 基本组件之 Date 类 基本组件之 Cale ...

  6. QuantLib 金融计算——高级话题之模拟跳扩散过程

    目录 QuantLib 金融计算--高级话题之模拟跳扩散过程 跳扩散过程 模拟算法 面临的问题 "脏"的方法 "干净"的方法 实现 示例 参考文献 如果未做特别 ...

  7. QuantLib 金融计算——基本组件之 Currency 类

    目录 QuantLib 金融计算--基本组件之 Currency 类 概述 构造函数 成员函数 如果未做特别说明,文中的程序都是 python3 代码. QuantLib 金融计算--基本组件之 Cu ...

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

    目录 QuantLib 金融计算--随机过程之概述 框架 用法与接口 如果未做特别说明,文中的程序都是 Python3 代码. QuantLib 金融计算--随机过程之概述 载入模块 import Q ...

  9. QuantLib 金融计算——随机过程之一般 Black Scholes 过程

    目录 QuantLib 金融计算--随机过程之一般 Black Scholes 过程 一般 Black Scholes 过程 如果未做特别说明,文中的程序都是 Python3 代码. QuantLib ...

随机推荐

  1. Kafka管理工具介绍

    Kafka内部提供了许多管理脚本,这些脚本都放在$KAFKA_HOME/bin目录下,而这些类的实现都是放在源码的kafka/core/src/main/scala/kafka/tools/路径下. ...

  2. 用 RPM 打包软件,第 1 部分

    http://www.ibm.com/developerworks/cn/linux/management/package/rpm/part1/ RPM(Red Hat Package Manager ...

  3. 全球数据库-->基金/管理产品-->分类/行业平均-->开放式分类

    SecID 招募书中所定净费率 换手率% 回报日期(每日) 计价货币 回报-本月以来(每日)计价货币 回报-本季以来(每日)计价货币 回报-本年以来(每日)计价货币 回报-1日(每日)计价货币 回报- ...

  4. 使用vim鼠标右键无法粘贴问题解决

    问题: Debian中通过终端使用vim,无法通过鼠标粘贴.这是由于一项默认的鼠标配置导致. 解决方法: vi /usr/share/vim/vim80/defaults.vim 查找set mous ...

  5. BFS入门

    #include<iostream> #include<cstring> #include<queue> using namespace std; #define ...

  6. 服务器上如何将D盘修改为E盘

    1.计算机管理→磁盘管理 2.右键点击需要调整的磁盘→更改驱动器号和路径 3.在弹出的设置框中→更改 4.点击右边的下拉箭头▼→选择一个盘符→确定 注意:如果盘符混乱,需要理顺,因为有些盘符占有了,不 ...

  7. Plupload 上传详细讲解,Plupload 多实例上传,Plupload多个上传按钮--推荐使用

    今天帮朋友解决  Plupload  上传的问题,查了很多资料,资料还是挺全的,但是有点零零散散的,故整理好,合并发出来. 本教程包括: Plupload  上传详细讲. Plupload  多实例上 ...

  8. win7更改路由器wifi 密码

    1.有线.无线都能进入192.168.1.1路由设置界面 (也可能是192.168.0.1看路由底面IP) ps: 无线(笔记本与路由没使用网线相连)情况下必须开启wifi连接上该路由才能进入. 无法 ...

  9. 終于解決调用wordpress 4.3 xmlrpc api 发布包含分类的文章时返回“抱歉,文章类型不支持您的分类法”错误的問題

    這個問題我找了很多資料都沒有明說是如何解決,后來突發奇想得出我的解決方案如下,所以特此記錄一下: object postId = blogService.NewPost(0,"admin&q ...

  10. EBS 并发程序运行信息

    --并发程序运行信息SELECT REQUEST_ID,       PROGRAM,       actual_start_date 开始日期,       ACTUAL_COMPLETION_DA ...