QuantLib 金融计算——自己动手封装 Python 接口(2)

目录

  • QuantLib 金融计算——自己动手封装 Python 接口(2)

    • 概述
    • 如何封装一项复杂功能?
      • 寻找最小功能集合的策略
    • 实践
      • 估计期限结构参数
      • 修改官方接口文件
    • 下一步的计划

QuantLib 金融计算——自己动手封装 Python 接口(2)

概述

对于一项简单功能,通常只需要包装少数几个类就可以,正如《自己动手封装 Python 接口(1)》演示的那样。

下面,将演示如何包装 QuantLib 中的复杂功能,最终实现从固息债交易数据中估计期限结构模型的参数

如何封装一项复杂功能?

经过一翻摸索后发现,要封装一项复杂功能,首先要找到最小功能集合,即这项功能直接或间接涉及的类和函数有哪些。然后,找到最小功能集合后再对涉及到的类或函数分别编写接口文件。最后,按照常规流程生成包装好的 Python 接口。

对于简单功能来说最小功能集合可能就是一两个类或函数。而对于复杂功能来说,寻找最小功能集合是一个递归的过程(A 用到 B,B 用到 C,...),最终可能找到很多类或函数需要包装。

寻找最小功能集合的策略

寻找最小功能集合有一些经验性的方法,以“从固息债交易数据中估计期限结构模型的参数”这项功能为例:

  1. 找到核心功能类,即 FittedBondDiscountCurve,最小功能集合要包含这个类、它的基类以及基类的基类,等等;
  2. 找到构造 FittedBondDiscountCurve 对象时涉及到一系列的类,例如 CalendarFittingMethod 等,这些类、它们的基类以及基类的基类也要包含在最小功能集合中;
  3. 找到 FittedBondDiscountCurve 成员函数涉及到一系列的类,这些类、它们的基类以及基类的基类也要包含在最小功能集合中;
  4. 把第 2 和第 3 步递归地进行下去,直到最小功能集合中的类和函数不再增加。

需要注意的是,到现在为止最小功能集合中出现的类有的可以发挥实际作用,例如 Date;而有的只是充当接口的基类,例如 FittingMethod,对于这些情况,要把它们能够发挥实际作用的派生类包含进最小功能集合。

实践

QuantLib-SWIG 从 1.16 开始修改了智能指针的包装方式,为了和最新版本保持一致,这里以 QuantLib 1.17 的 SWIG 接口文件为基础做适当修改,删去一些冗余代码,用以包装 QuantLib 1.15 的接口。

官方发布的接口文件中 FittingMethod 的构造函数不能接受 OptimizationMethod 对象,也不能进行 \(L^2\) 正则化约束。在本次自定义的接口文件中扩展了构造函数的接口,克服上述局限。

接口文件请见 QuantLibEx-SWIG

估计期限结构参数

《收益率曲线之构建曲线(5)》中的 C++ 代码翻译成 Python,验证封装后的接口是否可用。

import QuantLibEx as qlx

print(qlx.__version__)

bondNum = 16

cleanPrice = [100.4941, 103.5572, 104.4135, 105.0056, 99.8335, 101.25, 102.3832, 97.0053,
              99.5164, 101.2435, 104.0539, 101.15, 96.1395, 91.1123, 122.0027, 92.4369]
priceHandle = [qlx.QuoteHandle(qlx.SimpleQuote(p)) for p in cleanPrice]
issueYear = [1999, 1999, 2001, 2002, 2003, 1999, 2004, 2005,
             2006, 2007, 2003, 2008, 2005, 2006, 1997, 2007]
issueMonth = [qlx.February, qlx.October, qlx.January, qlx.January, qlx.May, qlx.January, qlx.January, qlx.April,
              qlx.April, qlx.September, qlx.January, qlx.January, qlx.January, qlx.January, qlx.July, qlx.January]
issueDay = [22, 22, 4, 9, 20, 15, 15, 26, 21, 17, 15, 8, 14, 11, 10, 12]

maturityYear = [2009, 2010, 2011, 2012, 2013, 2014, 2014, 2015,
                2016, 2017, 2018, 2019, 2020, 2021, 2027, 2037]

maturityMonth = [qlx.July, qlx.January, qlx.January, qlx.July, qlx.October, qlx.January, qlx.July, qlx.July,
                 qlx.September, qlx.September, qlx.January, qlx.March, qlx.July, qlx.September, qlx.July, qlx.March]

maturityDay = [15, 15, 4, 15, 20, 15, 15, 15,
               15, 15, 15, 15, 15, 15, 15, 15]

issueDate = []
maturityDate = []
for i in range(bondNum):
    issueDate.append(
        qlx.Date(issueDay[i], issueMonth[i], issueYear[i]))
    maturityDate.append(
        qlx.Date(maturityDay[i], maturityMonth[i], maturityYear[i]))

couponRate = [
    0.04, 0.055, 0.0525, 0.05, 0.038, 0.04125, 0.043, 0.035,
    0.04, 0.043, 0.0465, 0.0435, 0.039, 0.035, 0.0625, 0.0415]

# 配置 helper

frequency = qlx.Annual
dayCounter = qlx.Actual365Fixed(qlx.Actual365Fixed.Standard)
paymentConv = qlx.Unadjusted
terminationDateConv = qlx.Unadjusted
convention = qlx.Unadjusted
redemption = 100.0
faceAmount = 100.0
calendar = qlx.Australia()

today = calendar.adjust(qlx.Date(30, qlx.January, 2008))
qlx.Settings.instance().evaluationDate = today

bondSettlementDays = 0
bondSettlementDate = calendar.advance(
    today,
    qlx.Period(bondSettlementDays, qlx.Days))

instruments = []
maturity = []

for i in range(bondNum):
    bondCoupon = [couponRate[i]]

    schedule = qlx.Schedule(
        issueDate[i],
        maturityDate[i],
        qlx.Period(frequency),
        calendar,
        convention,
        terminationDateConv,
        qlx.DateGeneration.Backward,
        False)

    helper = qlx.FixedRateBondHelper(
        priceHandle[i],
        bondSettlementDays,
        faceAmount,
        schedule,
        bondCoupon,
        dayCounter,
        paymentConv,
        redemption)

    maturity.append(dayCounter.yearFraction(
        bondSettlementDate, helper.maturityDate()))

    instruments.append(helper)

accuracy = 1.0e-6
maxEvaluations = 5000
weights = qlx.Array()

# 正则化条件

l2Ns = qlx.Array(4, 0.5)
guessNs = qlx.Array(4)
guessNs[0] = 4 / 100.0
guessNs[1] = 0.0
guessNs[2] = 0.0
guessNs[3] = 0.5

l2Sv = qlx.Array(6, 0.5)
guessSv = qlx.Array(6)
guessSv[0] = 4 / 100.0
guessSv[1] = 0.0
guessSv[2] = 0.0
guessSv[3] = 0.0
guessSv[4] = 0.2
guessSv[5] = 0.15

optMethod = qlx.LevenbergMarquardt()

# 拟合方法

nsf = qlx.NelsonSiegelFitting(
    weights, optMethod, l2Ns)
svf = qlx.SvenssonFitting(
    weights, optMethod, l2Sv)

tsNelsonSiegel = qlx.FittedBondDiscountCurve(
    bondSettlementDate,
    instruments,
    dayCounter,
    nsf,
    accuracy,
    maxEvaluations,
    guessNs,
    1.0)

tsSvensson = qlx.FittedBondDiscountCurve(
    bondSettlementDate,
    instruments,
    dayCounter,
    svf,
    accuracy,
    maxEvaluations,
    guessSv)

print("NelsonSiegel Results: \t", tsNelsonSiegel.fitResults().solution())
print("Svensson Results: \t\t", tsSvensson.fitResults().solution())

# NelsonSiegel Results:     [ 0.0500803; -0.0105414; -0.0303842; 0.456529 ]
# Svensson Results:         [ 0.0431095; -0.00716036; -0.0340932; 0.0391339; 0.228995; 0.117208 ]

所得结果和《收益率曲线之构建曲线(5)》中的完全一致。

修改官方接口文件

如果已经安装了 1.16 以后的 QuantLib,只要对官方接口文件稍加修改再重新包装 Python 接口,就可以扩展 FittingMethod 的构造函数,使其能接受 OptimizationMethod 对象,并能进行正则化。

NelsonSiegelFitting 为例,需要在 fittedbondcurve.i 文件中用

class NelsonSiegelFitting : public FittingMethod {
  public:
    NelsonSiegelFitting(
        const Array& weights = Array(),
        boost::shared_ptr< OptimizationMethod > optimizationMethod = boost::shared_ptr< OptimizationMethod >(),
        const Array &l2 = Array());
};

替换

class NelsonSiegelFitting : public FittingMethod {
  public:
    NelsonSiegelFitting(const Array& weights = Array());
};

下一步的计划

  1. 包装 QuantLibEx 中的几个期限结构模型;
  2. scipy 的优化算法引擎要相较于 QuantLib 自身提供的要更丰富,尝试使 FittingMethod 能接受 scipy 的算法。

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

时间: 2024-08-30 02:16:23

QuantLib 金融计算——自己动手封装 Python 接口(2)的相关文章

QuantLib 金融计算——自己动手封装 Python 接口(1)

目录 QuantLib 金融计算--自己动手封装 Python 接口(1) 概述 QuantLib 如何封装 Python 接口? 自己封装 Python 接口 封装 Array 和 Matrix 类 QuantLibEx 和官方包混合使用 附录:接口文件.setup.py 和 __init__.py QuantLib 金融计算--自己动手封装 Python 接口(1) 概述 QuantLib 已经开始在 PyPi 上发布封装好的 Python 接口,安装和使用非常方便,与普通的包别无二致.并且

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 金融计算——基本组件之 InterestRate 类

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

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

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

QuantLib 金融计算

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

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 金融计算——数学工具之求解器

目录 QuantLib 金融计算--数学工具之求解器 概述 调用方式 非 Newton 算法(不需要导数) Newton 算法(需要导数) 如果未做特别说明,文中的程序都是 Python3 代码. QuantLib 金融计算--数学工具之求解器 载入模块 import QuantLib as ql import scipy from scipy.stats import norm print(ql.__version__) 1.12 概述 QuantLib 提供了多种类型的一维求解器,用以求解单

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

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