欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-09-04 20:28:03
[TOC] QuantLib 金融计算——自己动手封装 Python 接口(3) 概述 承接 "《自己动手封装 Python 接口(2)》" 中留下的问题,即封装 "QuantLibEx" 中的几个期限结构模型。 如何封装源代码? 与前一篇文章中的情况不同,要封装的程序不是已经编译好的库文件,而是 ......

quantlib 金融计算——自己动手封装 python 接口(3)

概述

承接《自己动手封装 python 接口(2)》中留下的问题,即封装 quantlibex 中的几个期限结构模型。

如何封装源代码?

与前一篇文章中的情况不同,要封装的程序不是已经编译好的库文件,而是 c++ 源代码。

swig 可以从源代码的层面封装 c++ 接口,一方面要提供头文件,告知 swig 类、函数等的声明;另一方面要提供源文件,让 swig 知道方法的实现,swig 会自动对源文件进行编译,并最终链接到生成的 python 接口中。

实践

幸运的是 quantlibex 中几个 ns 型期限结构模型的构造函数没有引入新的类型,所以“最小功能集合”没有变。

要封装这几个模型,只需对 fittedbondcurve.isetup.py 稍加修改。在 fittedbondcurve.i 中编写接口代码,在 setup.py 添加头文件路径和几个源文件就可以了。

六个 ns 型期限结构模型的参数估计

把中的 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

l2asv = qlx.array(6, 0.5)
guessasv = qlx.array(6)
guessasv[0] = 4 / 100.0
guessasv[1] = 0.0
guessasv[2] = 0.0
guessasv[3] = 0.0
guessasv[4] = 0.2
guessasv[5] = 0.3

l2bc = qlx.array(5, 0.5)
guessbc = qlx.array(5)
guessbc[0] = 4 / 100.0
guessbc[1] = 0.0
guessbc[2] = 0.0
guessbc[3] = 0.0
guessbc[4] = 0.2

l2bl = qlx.array(5, 0.5)
guessbl = qlx.array(5)
guessbl[0] = 4 / 100.0
guessbl[1] = 0.0
guessbl[2] = 0.0
guessbl[3] = 0.5
guessbl[4] = 0.5

optmethod = qlx.levenbergmarquardt()

# 拟合方法

nsf = qlx.nelsonsiegelfitting(
    weights, optmethod, l2ns)
svf = qlx.svenssonfitting(
    weights, optmethod, l2sv)
asvf = qlx.adjustedsvenssonfitting(
    weights, optmethod, l2asv)
dlf = qlx.dieboldlifitting(
    0.5, weights, optmethod)
bcf = qlx.bjorkchristensenfitting(
    weights, optmethod, l2bc)
blf = qlx.blissfitting(
    weights, optmethod, l2bl)

tsnelsonsiegel = qlx.fittedbonddiscountcurve(
    bondsettlementdate,
    instruments,
    daycounter,
    nsf,
    accuracy,
    maxevaluations,
    guessns,
    1.0)

tssvensson = qlx.fittedbonddiscountcurve(
    bondsettlementdate,
    instruments,
    daycounter,
    svf,
    accuracy,
    maxevaluations,
    guesssv)

tsadjustedsvensson = qlx.fittedbonddiscountcurve(
    bondsettlementdate,
    instruments,
    daycounter,
    asvf,
    accuracy,
    maxevaluations,
    guessasv)

tsdieboldli = qlx.fittedbonddiscountcurve(
    bondsettlementdate,
    instruments,
    daycounter,
    dlf,
    accuracy,
    maxevaluations)

tsbjorkchristensen = qlx.fittedbonddiscountcurve(
    bondsettlementdate,
    instruments,
    daycounter,
    bcf,
    accuracy,
    maxevaluations,
    guessbc)

tsbliss = qlx.fittedbonddiscountcurve(
    bondsettlementdate,
    instruments,
    daycounter,
    blf,
    accuracy,
    maxevaluations,
    guessbl)

print("nelsonsiegel results: \t\t", tsnelsonsiegel.fitresults().solution())
print("svensson results: \t\t\t", tssvensson.fitresults().solution())
print("adjustedsvensson results: \t", tsadjustedsvensson.fitresults().solution())
print("dieboldli results: \t\t\t", tsdieboldli.fitresults().solution())
print("bjorkchristensen results: \t", tsbjorkchristensen.fitresults().solution())
print("bliss results: \t\t\t\t", tsbliss.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 ]
adjustedsvensson results:   [ 0.0506269; -0.0116339; 0.0029305; -0.0135686; 0.179066; 0.267767 ]
dieboldli results:          [ 0.0496643; -0.00879931; -0.0329267 ]
bjorkchristensen results:   [ 0.0508039; -0.0555185; 0.0115282; 0.0415581; 0.227838 ]
bliss results:              [ 0.0500892; -0.0106013; -0.0315605; 0.513831; 0.456329 ]

所得结果和中的完全一致。

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