数学工具
求解器
QuantLib 提供了多种一维求解器类型,用于求解单参数函数的根。

其中
是定义在实数域上的函数。
QuantLib提供的求解器类型包括:
布伦特
二分法
正割法
里德尔
牛顿法(需要成员函数derivative,计算导数)
FalsePosition
这些求解器的构造函数是默认构造函数,不接受参数。 例如,构建Brent求解器实例的语句如下:
mySolv = Brent()
有两种方式可以调用求解器的成员函数:
mySolv.solve(f, accuracy, guess, step)
mySolv.solve(f, accuracy, guess, xMin, xMax)
f |
单参数函数或函数对象,返回值为浮点数 |
accuracy |
浮点数,表示用于停止计算时的求解精度 |
guess |
浮点数,根的初始猜测值 |
step |
浮点数。在第一种调用方法中,根的范围没有限制。算法需要自行搜索来确定范围。step指定搜索算法的步长。 |
xMin, xMax |
浮点数,左右区间范围 |
ql.Settings.instance().evaluationDate = ql.Date(15,6,2020)
crv = ql.FlatForward(2, ql.TARGET(), 0.05, ql.Actual360())
yts = ql.YieldTermStructureHandle(crv)
engine = ql.DiscountingSwapEngine(yts)
schedule = ql.MakeSchedule(ql.Date(15,9,2020), ql.Date(15,9,2021), ql.Period('6M'))
index = ql.Euribor3M(yts)
floatingLeg = ql.IborLeg([100], schedule, index)
def swapFairRate(rate):
fixedLeg = ql.FixedRateLeg(schedule, ql.Actual360(), [100.], [rate])
swap = ql.Swap(fixedLeg, floatingLeg)
swap.setPricingEngine(engine)
return swap.NPV()
solver = ql.Brent()
accuracy = 1e-5
guess = 0.0
step = 0.001
solver.solve(swapFairRate, accuracy, guess, step)
集成
高斯求积法
高斯求积法用于计算特定区间上的积分。例如,高斯-勒让德方法计算区间[-1,1]上的定积分。
import numpy as np
import QuantLib as ql
f = lambda x: x**2
g = lambda x: np.exp(x)
quad_ql_legendre = ql.GaussLegendreIntegration(128)
quad_ql_legendre(f), quad_ql_legendre(g)
Scipy也有一个我们可以比较的实现:
from scipy.integrate import quad
quad(f, -1, 1)[0], quad(g, -1, 1)[0]
Scipy要求一个区间[a,b]来进行运算。我们可以通过使用包装函数缩放输入参数,在quantlib中实现相同的功能:
def quad_ql_ab(f, a, b, quad):
multiplier, ratio = (b+a) / 2, (b-a) / 2
y = lambda x: f(ratio*x + multiplier)
return quad(y) * ratio
quad_ql = ql.GaussLegendreIntegration(128)
quad_ql_ab(f, -2, 2, quad_ql), quad_ql_ab(g, -2, 2, quad_ql), quad(f, -2, 2)[0], quad(g, -2, 2)[0]
其他支持的求积方法包括:
高斯-勒让德积分,
高斯-切比雪夫积分,
高斯-切比雪夫第二类积分,
高斯-拉盖尔积分,
高斯-埃尔米特积分,
GaussJacobiIntegration,
高斯双曲积分,
高斯-盖根鲍尔积分
The intervals and additional parameters for each quadrature varies (see eg. https://mathworld.wolfram.com/GaussianQuadrature.html)
插值
插值是量化金融中最常用的工具之一。标准应用场景包括收益率曲线的插值、波动率微笑曲线的插值以及波动率曲面的插值。quantlib-python提供了以下一维和二维插值方法:
- XXXInterpolation(x, y)
x : 浮点数序列,多个离散参数
y : 浮点数序列,表示与参数x对应的函数值,长度与x相同
插值类定义了__call__方法。插值类对象的使用方式如下,可以像函数一样调用
i(x, allowExtrapolation)
x : 浮点数,需要插值的点
allowExtrapolation : boolean。将allowExtrapolation设置为True表示允许外推。默认值为False。
一维插值方法
LinearInterpolation (一维)
LogLinearInterpolation (一维)
CubicInterpolation (一维)
LogCubicInterpolation (一维)
ForwardFlatInterpolation (一维)
BackwardFlatInterpolation (一维)
LogParabolicInterpolation (一维)
import QuantLib as ql
import numpy as np
import matplotlib.pyplot as plt
X = [1., 2., 3., 4., 5.]
Y = [0.5, 0.6, 0.7, 0.8, 0.9]
methods = {
'Linear Interpolation': ql.LinearInterpolation(X, Y),
'LogLinearInterpolation': ql.LogLinearInterpolation(X, Y),
'CubicNaturalSpline': ql.CubicNaturalSpline(X, Y),
'LogCubicNaturalSpline': ql.LogCubicNaturalSpline(X, Y),
'ForwardFlatInterpolation': ql.ForwardFlatInterpolation(X, Y),
'BackwardFlatInterpolation': ql.BackwardFlatInterpolation(X, Y),
'LogParabolic': ql.LogParabolic(X, Y)
}
xx = np.linspace(1, 10)
fig = plt.figure(figsize=(15,4))
plt.scatter(X, Y, label='Original Data')
for name, i in methods.items():
yy = [i(x, allowExtrapolation=True) for x in xx]
plt.plot(xx, yy, label=name);
plt.legend();
二维插值方法
双线性插值 (二维)
BicubicSpline (二维)
import pandas as pd
X = [1., 2., 3., 4., 5.]
Y = [0.6, 0.7, 0.8, 0.9]
Z = [[(x-3)**2 + y for x in X] for y in Y]
df = pd.DataFrame(Z, columns=X, index=Y)
i = ql.BilinearInterpolation(X, Y, Z)
XX = np.linspace(0, 5, 9)
YY = np.linspace(0.55, 1.0, 10)
extrapolated = pd.DataFrame(
[[i(x,y, True) for x in XX] for y in YY],
columns=XX,
index=YY)
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_title("Surface Interpolation")
Xs, Ys = np.meshgrid(XX, YY)
surf = ax.plot_surface(
Xs, Ys, extrapolated, rstride=1, cstride=1, cmap=cm.coolwarm
)
fig.colorbar(surf, shrink=0.5, aspect=5);
优化
随机数生成器
Quantlib-Python 提供以下三种均匀分布的(伪)随机数生成器:
ql.KnuthUniformRng, Knuth算法
ql.LecuyerUniformRng, L'Ecuyer算法
ql.MersenneTwisterUniformRng,著名的Mersenne-Twister算法
随机数生成器的构造函数,
- RandomNumberGenerator(seed)
其中seed是一个整数,默认值为0,用作初始化相应确定性序列的种子
随机数生成器的成员函数:
next() : 返回一个SampleNumber对象作为模拟的结果。
r = rng.next()
v = r.value(r)
用户通过重复调用成员函数next()获取一系列随机数。 需要注意的是,r的类型为SampleNumber,对应的浮点数需要通过调用value()来获取。
在随机模拟中最常见的分布是正态分布。quantlib-python提供了四种类型的正态分布随机数生成器:
CentralLimit[X]GaussianRng
BoxMuller[X]GaussianRng
MoroInvCumulative[X]GaussianRng
InvCumulative[X]GaussianRng
其中[X]指代均匀随机数生成器。
具体来说,有12种类型的4种生成器:
CentralLimitLecuyerGaussianRng
CentralLimitKnuthGaussianRng
CentralLimitMersenneTwisterGaussianRng
BoxMullerLecuyerGaussianRng
BoxMullerKnuthGaussianRng
BoxMullerMersenneTwisterGaussianRng
Moro逆累积Lecuyer高斯随机数生成器
Moro逆累积Knuth高斯随机数生成器
MoroInvCumulativeMersenneTwisterGaussianRng
逆累积Lecuyer高斯随机数生成器
InvCumulativeKnuthGaussianRng
InvCumulativeMersenneTwisterGaussianRng
随机数生成器的构造函数:
- GaussianRandomNumberGenerator(RandomNumberGenerator)
BoxMullerMersenneTwisterGaussianRng 分布式随机数生成器接受对应的均匀分布随机数生成器作为输入源。
以BoxMullerMersenneTwisterGaussianRng为例,您需要配置一个MersenneTwisterUniformRng对象作为随机数源,并使用经典的Box-Muller算法来获取正态分布的随机数。
seed = 12324
unifMt = ql.MersenneTwisterUniformRng(seed)
bmGauss = ql.BoxMullerMersenneTwisterGaussianRng(unifMt)
for i in range(5):
print(bmGauss.next().value())
与之前描述的“伪”随机数相比,随机模拟中另一种重要的随机数类型是“准”随机数,也称为低偏差序列。由于具有更好的收敛性,准随机数常用于高维随机变量的模拟。quantlib-python提供了两种准随机数类型,
HaltonRsg : Halton序列
SobolRsg : Sobol序列
HaltonRsg
- HaltonRsg(dimensionality, seed, randomStart, randomShift)
其中,
dimensionality : 整数,设置维度;
seed : 一个整数,默认值为0,用作初始化相应确定性序列的种子;
randomStart : boolean, 默认为 True, 是否随机开始;
randomShift : Boolean, 默认为 False , 是否随机偏移。
HaltonRsg的成员函数,
nextSequence() : 返回一个SampleRealVector对象作为模拟结果;
lastSequence() : 返回一个SampleRealVector对象作为前一次模拟的结果;
dimension() : 返回维度。
SobolRsg
- SobolRsg(dimensionality, seed, directionIntegers=Jaeckel)
其中,
dimensionality : 整数,设置维度;
seed : 一个整数,默认值为0,用作初始化相应确定性序列的种子;
directionIntegers : quantlib-python的内置变量。默认值为SobolRsg.Jaeckel,用于初始化Sobol序列。
SobolRsg的成员函数,
nextSequence() : 返回一个SampleRealVector对象作为模拟结果;
lastSequence() : 返回一个SampleRealVector对象作为前一次模拟的结果;
dimension() : 返回维度。
skipTo(n) : n为整数,跳转到采样结果的第n个维度;
nextInt32Sequence() : 返回一个IntVector对象。
路径生成器
QuantLib 提供了多个封装函数,用于从给定的随机过程生成样本路径
高斯多路径生成器
使用伪随机数从任意随机过程生成路径
- ql.GaussianMultiPathGenerator(stochasticProcess, times, sequenceGenerator, brownianBridge=False)
timestep, length, numPaths = 24, 2, 2**15
today = ql.Date().todaysDate()
riskFreeTS = ql.YieldTermStructureHandle(ql.FlatForward(today, 0.05, ql.Actual365Fixed()))
dividendTS = ql.YieldTermStructureHandle(ql.FlatForward(today, 0.01, ql.Actual365Fixed()))
initialValue = ql.QuoteHandle(ql.SimpleQuote(100))
v0, kappa, theta, rho, sigma = 0.005, 0.8, 0.008, 0.2, 0.1
hestonProcess = ql.HestonProcess(riskFreeTS, dividendTS, initialValue, v0, kappa, theta, sigma, rho)
times = ql.TimeGrid(length, timestep)
dimension = hestonProcess.factors()
rng = ql.UniformRandomSequenceGenerator(dimension * timestep, ql.UniformRandomGenerator())
sequenceGenerator = ql.GaussianRandomSequenceGenerator(rng)
pathGenerator = ql.GaussianMultiPathGenerator(hestonProcess, list(times), sequenceGenerator, False)
# paths[0] will contain spot paths, paths[1] will contain vol paths
paths = [[] for i in range(dimension)]
for i in range(numPaths):
samplePath = pathGenerator.next()
values = samplePath.value()
spot = values[0]
for j in range(dimension):
paths[j].append([x for x in values[j]])
GaussianSobolMultiPathGenerator
使用低差异数从任意随机过程生成路径
- ql.GaussianSobolMultiPathGenerator(stochasticProcess, times, sequenceGenerator, brownianBridge=False)
timestep, length, numPaths = 24, 2, 2**15
today = ql.Date().todaysDate()
riskFreeTS = ql.YieldTermStructureHandle(ql.FlatForward(today, 0.05, ql.Actual365Fixed()))
dividendTS = ql.YieldTermStructureHandle(ql.FlatForward(today, 0.01, ql.Actual365Fixed()))
initialValue = ql.QuoteHandle(ql.SimpleQuote(100))
v0, kappa, theta, rho, sigma = 0.005, 0.8, 0.008, 0.2, 0.1
hestonProcess = ql.HestonProcess(riskFreeTS, dividendTS, initialValue, v0, kappa, theta, sigma, rho)
times = ql.TimeGrid(length, timestep)
dimension = hestonProcess.factors()
rng = ql.UniformLowDiscrepancySequenceGenerator(dimension * timestep)
sequenceGenerator = ql.GaussianLowDiscrepancySequenceGenerator(rng)
pathGenerator = ql.GaussianSobolMultiPathGenerator(hestonProcess, list(times), sequenceGenerator, False)
# paths[0] will contain spot paths, paths[1] will contain vol paths
paths = [[] for i in range(dimension)]
for i in range(numPaths):
samplePath = pathGenerator.next()
values = samplePath.value()
spot = values[0]
for j in range(dimension):
paths[j].append([x for x in values[j]])
统计
惯例计算器
BlackDelta计算器
一个计算器类,用于计算外汇风格delta-期限-波动率报价的相关执行价(参见Reiswich D., Wystup U., 2010. A Guide to FX Options Quoting Conventions)
- ql.BlackDeltaCalculator(optionType, deltaType, spot, domesticDcf, foreignDcf, volRootT)
import numpy as np
today = ql.Date().todaysDate()
dayCounter = ql.Actual365Fixed()
spot = 100
rd, rf = 0.02, 0.05
ratesTs = ql.YieldTermStructureHandle(ql.FlatForward(today, rd, dayCounter))
dividendTs = ql.YieldTermStructureHandle(ql.FlatForward(today, rf, dayCounter))
# Details about the delta quote
optionType = ql.Option.Put
vol = 0.07
maturity = 1.0
deltaType = ql.DeltaVolQuote.Fwd # Also supports: Spot, PaSpot, PaFwd
# Set up the calculator
localDcf, foreignDcf = ratesTs.discount(maturity), dividendTs.discount(maturity)
stdDev = np.sqrt(maturity) * vol
calc = ql.BlackDeltaCalculator(optionType, deltaType, spot, localDcf, foreignDcf, stdDev)
计算给定看涨/看跌期权delta对应的执行价(看跌期权的delta为负值)
delta = -0.3
calc.strikeFromDelta(delta)
或者如果这是一个ATM报价,请指定ATM惯例
atmType = ql.DeltaVolQuote.AtmFwd # Also supports: AtmSpot, AtmDeltaNeutral, AtmVegaMax, AtmGammaMax, AtmPutCall50
calc.atmStrike(atmType)