程式

QuantLib Python:如何計算不規則現金流的持續時間和凸度?我可以使用 SimpleCashFlow 還是必須定義自定義債券?

  • February 7, 2021

我有兩個問題:

如果我想對一組不規則現金流進行折現,我可以使用 SimpleCashFlow 類,或者使用自定義現金流定義債券(感謝 Ballabio 和 David Duarte 之前對此的澄清。我在下面複製了一個玩具範例。

  1. 但是,我也可以使用 SimpleCashFlow 計算久期和凸性嗎,還是僅適用於債券?

我在文件中看到 CashFlows 確實具有durationandconvexity方法,但我似乎無法正確使用語法。

我的玩具範例的最後幾行是我嘗試過的 - 無濟於事。

  1. 請問這是在哪裡記錄的,或者如何解釋文件? 我寫的行似乎與我在https://quantlib-python-docs.readthedocs.io/en/latest/cashflows.html?highlight=duration#id5上找到的語法相匹配,但顯然我錯了,因為它們沒有工作。

相反,如果我搜尋 github https://rkapl123.github.io/QLAnnotatedSource/d3/d50/struct_quant_lib_1_1_duration.html ,我真的完全不了解語法應該是什麼樣子。

**任何人都可以請我指出哪些文件/在哪裡解釋正確的語法應該是什麼?我基本上處於無法理解文件的位置,即使是最平庸的計算也必須尋求幫助。**謝謝!

import QuantLib as ql
import pandas as pd
from datetime import date
import numpy as np

d1 = ql.Date(15,1,2001)
ql.Settings.instance().setEvaluationDate(d1)
cfs = [ql.SimpleCashFlow(0, d1),
       ql.SimpleCashFlow(110, d1 + 365)]

calc_date = d1
risk_free_rate = 0.1
curve_act_365 = ql.YieldTermStructureHandle(
                    ql.FlatForward(calc_date, risk_free_rate, ql.Actual365Fixed() , ql.Compounded, ql.Annual ))

curve_30_360 = ql.YieldTermStructureHandle(
                    ql.FlatForward(calc_date, risk_free_rate, ql.Thirty360(), ql.Compounded, ql.Annual  ))

# The present value is the same 9as it should be!)
# whether I calculate it as
# 1) cashflows - act365
# 2) cashflows - 30/360
# 3) custom bond - act465

pv_act_365 = ql.CashFlows.npv(cfs, curve_act_365, True)
pv_30_360 = ql.CashFlows.npv(cfs, curve_30_360, True)

custom_bond = ql.Bond(0, ql.TARGET(), 100.0, ql.Date(), ql.Date(), cfs)
bond_engine = ql.DiscountingBondEngine(curve_act_365)
custom_bond.setPricingEngine(bond_engine)
pv_bond = custom_bond.NPV()

# I can also use the custom bond to calculate duration and convexity

y = ql.InterestRate(0.1, ql.Actual365Fixed(), ql.Compounded, ql.Annual)
dur_bond = ql.BondFunctions.duration(custom_bond, y, ql.Duration.Macaulay)
conv_bond = ql.BondFunctions.convexity(custom_bond, y)

# manually recalculating the convexity just as a check
conv_check = 1 / (100 * 1.1**2)*110* (1+1**2)/(1.1)

# Can I use the CashFlows class to calculate duration and convexity, too?
# I have tried all the combinations below but none works

cf_dur = ql.CashFlows.duration(cfs, y, ql.Duration.Macaulay)

leg = ql.Leg(cfs)
cf_dur = ql.CashFlows.duration(leg, y, ql.Duration.Macaulay)

cf_dur = ql.CashFlows.duration(leg, 0.1, ql.Duration.Macaulay, False)

cf_conv = x = ql.CashFlows.convexity(cfs, y)

根據弗朗西斯的回答進行更新:

  1. 因此,duration 函式可以採用日期列表,也可以採用從同一列表創建的 Leg 對象,對吧?兩者有什麼區別嗎?
  2. 文件說明 thatsettlementDate = ql.Date()和 that npvDate = ql.Date()。這是否意味著 ql.Date() 是預設值?或者它們是 ql.Date() 類型的?我不明白,因為執行 ql.Date() 返回一個空對象。我本來希望 ql.Date()等於今天的日期,或者用ql.Settings.instance().setEvaluationDate(mydate).

我想你幾乎兩者都有。您只是缺少 anInterestRateincludeSettlementDateFlows布爾標誌的組合。以下作品:

import QuantLib as Ql
import logging
ql = Ql

# Set up logging
numeric_level = getattr(logging, 'INFO', None)
logging.basicConfig(level=numeric_level, format='%(asctime)s %(levelname)-8s %(message)s', datefmt='%Y-%m-%d %H:%M:%S')

d1 = ql.Date(15, 1, 2001)
ql.Settings.instance().setEvaluationDate(d1)
cfs = [ql.SimpleCashFlow(0, d1), ql.SimpleCashFlow(110, d1 + 365)]

calc_date = d1
risk_free_rate = 0.1
curve_act_365 = ql.YieldTermStructureHandle(
   ql.FlatForward(calc_date, risk_free_rate, ql.Actual365Fixed(), ql.Compounded, ql.Annual))

curve_30_360 = ql.YieldTermStructureHandle(
   ql.FlatForward(calc_date, risk_free_rate, ql.Thirty360(), ql.Compounded, ql.Annual))

# The present value is the same 9as it should be!)
# whether I calculate it as
# 1) cashflows - act365
# 2) cashflows - 30/360
# 3) custom bond - act465

pv_act_365 = ql.CashFlows.npv(cfs, curve_act_365, True)
logging.info('pv_act_365: %f', pv_act_365)

pv_30_360 = ql.CashFlows.npv(cfs, curve_30_360, True)
logging.info('pv_30_360: %f', pv_30_360)

custom_bond = ql.Bond(0, ql.TARGET(), 100.0, ql.Date(), ql.Date(), cfs)
bond_engine = ql.DiscountingBondEngine(curve_act_365)
custom_bond.setPricingEngine(bond_engine)
pv_bond = custom_bond.NPV()
logging.info('pv_bond: %f', pv_bond)

# I can also use the custom bond to calculate duration and convexity
y = ql.InterestRate(0.1, ql.Actual365Fixed(), ql.Compounded, ql.Annual)
dur_bond = ql.BondFunctions.duration(custom_bond, y, ql.Duration.Macaulay)
conv_bond = ql.BondFunctions.convexity(custom_bond, y)
logging.info('dur_bond: %f', dur_bond)
logging.info('conv_bond: %f', conv_bond)

# manually recalculating the convexity just as a check
conv_check = 1 / (100 * 1.1 ** 2) * 110 * (1 + 1 ** 2) / 1.1
logging.info('conv_check: %f', conv_check)

# Can I use the CashFlows class to calculate duration and convexity, too?
# I have tried all the combinations below but none works

# cf_dur = ql.CashFlows.duration(cfs, y, ql.Duration.Macaulay)
# logging.info('cf_dur: %f', cf_dur)

leg = ql.Leg(cfs)
# cf_dur = ql.CashFlows.duration(leg, y, ql.Duration.Macaulay)
# logging.info('cf_dur: %f', cf_dur)

cf_dur = ql.CashFlows.duration(leg, y, ql.Duration.Macaulay, False)
logging.info('cf_dur: %f', cf_dur)

cf_conv = x = ql.CashFlows.convexity(cfs, y, False)
logging.info('cf_conv: %f', cf_conv)

和輸出

2021-02-07 20:09:07 INFO     pv_act_365: 100.000000
2021-02-07 20:09:07 INFO     pv_30_360: 100.000000
2021-02-07 20:09:07 INFO     pv_bond: 100.000000
2021-02-07 20:09:07 INFO     dur_bond: 1.000000
2021-02-07 20:09:07 INFO     conv_bond: 1.652893
2021-02-07 20:09:07 INFO     conv_check: 1.652893
2021-02-07 20:09:07 INFO     cf_dur: 1.000000
2021-02-07 20:09:07 INFO     cf_conv: 1.652893

為了完整起見,我也應該在此處連結到文件的相關部分:

對已編輯問題中提出的附加點的回答:

  1. 提供現金流量清單與提供 a 之間沒有區別Leg。在底層 C++ 程式碼中,這裡QuantLib::Leg只是一個typedef現金流量向量。
  2. 理解這裡邏輯的最簡單方法是查看底層 C++ 程式碼。如果settlementDate為空日期,則將其作為評估日期,即Settings::instance().evaluationDate()在 C++ 中。如果npvDate為空,則settlementDate在必要的情況下,在上句調整後作為 ,。

引用自:https://quant.stackexchange.com/questions/61015