Quantlib,调节债券现金流到期收益率的困难

问题描述 投票:0回答:1

我在协调现金流的到期收益率计算时遇到问题。

在代码中,我采用日期和金额向量来创建 BondLeg,并为其分配 dirty_value。

我使用 ql.Cashflows.yieldRate 来计算年复利和连续复利到期收益率。

我使用与计算收益率相同的日数基础生成日期的yearFraction。

然后,我使用 PYOMO 非线性优化求解器 (ipopt) 使用年份分数、现金流量和 dirty_value 来求解到期收益率。

PYOMO 年复利收益率与 Quantlib 收益率相差在 1bp 以内。然而,Quantlib 连续复合收益率比 PYOMO 收益率高 13bp。

我的 Jupyter Notebook 中的代码如下:

进口

import numpy as np
import QuantLib as ql

import pyomo.environ as pyo
from pyomo.opt import SolverFactory

ql.Settings.instance().evaluationDate = ql.Date(30,6,2023)

现金流和肮脏价值

dates = [ql.Date(14,11,2023), 
         ql.Date(14,11,2024), 
         ql.Date(14,11,2025), 
         ql.Date(16,11,2026), 
         ql.Date(15,11,2027), 
         ql.Date(14,11,2028), 
         ql.Date(14,11,2029), 
         ql.Date(14,11,2030), 
         ql.Date(14,11,2031), 
         ql.Date(15,11,2032)]

amounts = [84070, 
           84070, 
           84070, 
           84537.05555555558,
           65131.50532953604,
           65131.50532953604,
           65312.930135468014,
           65312.930135468014,
           65312.930135468014,
           1065494.3549413998]


dirty_val = 1050876.388888889


Quantlib 代码

BondLeg = ql.Leg([ql.SimpleCashFlow(amt, dt) for dt,amt in zip(dates,amounts)])

ql_ra = ql.CashFlows.yieldRate(BondLeg, dirty_val, ql.Actual365Fixed(), ql.Compounded, ql.Annual, True)
ql_rc = ql.CashFlows.yieldRate(BondLeg, dirty_val, ql.Actual365Fixed(), ql.Compounded, ql.Continuous, True)

使用 Quantlib 生成 YearFractions

year_fracs = [ql.Actual365Fixed().yearFraction(ql.Date(30,6,2023),dt) for dt in dates]

periods = np.array([frac for frac in year_fracs])
p_int = np.int_(periods)
p_frac = periods - p_int

amount_vec = np.array(amounts)

使用 PYOMO Solver 计算

年复利收益率

model_ra = pyo.ConcreteModel()

# Decision Variables
model_ra.ra = pyo.Var(domain = pyo.NonNegativeReals, initialize=0.05)
ra = model_ra.ra


# Objective Function

def ra_objective_rule(model_ra):
    
    return (amount_vec.dot(1/(((1+ra)**p_int)* (1+(ra*p_frac)))) - dirty_val)**2

model_ra.objf = pyo.Objective(rule=ra_objective_rule, sense=pyo.minimize)

# Constraints


Solver = SolverFactory('ipopt')

results_ra = Solver.solve(model_ra)

print(results_ra)
print(f'Objective Function = {model_ra.objf()}')
print(f'ra = {ra()}')

不断复利收益

model_rc = pyo.ConcreteModel()

# Decision Variables
model_rc.rc = pyo.Var(domain = pyo.NonNegativeReals, initialize=0.05)
rc = model_rc.rc


# Objective Function

def rc_objective_rule(model_rc):
     
    return (amount_vec.dot(np.array([pyo.exp(-p*rc) for p in periods])) - dirty_val)**2
    
model_rc.objf = pyo.Objective(rule=rc_objective_rule, sense=pyo.minimize)

# Constraints


Solver = SolverFactory('ipopt')

results_rc = Solver.solve(model_rc)

print(results_rc)
print(f'Objective Function = {model_rc.objf()}')
print(f'rc = {rc()}')

结果比较

print(f'QuantLib - Annually Compounded Rate : {ql_ra:.4%}')
print(f'QuantLib - Continuously Compounded Rate : {ql_rc:.4%}')

print(f'PYOMO - Annually Compounded Rate : {ra.value:.4%}')
print(f'PYOMO - Continuously Compounded Rate : {rc.value:.4%}')

QuantLib - 年复合利率:7.3623% QuantLib - 连续复利率:7.2315%

PYOMO - 年复合利率:7.3526% PYOMO - 连续复利率:7.1039%

python pyomo quantitative-finance quantlib
1个回答
0
投票

[从 QuantLib 邮件列表复制答案,以防有人通过搜索到达这里]

上面代码中的调用,

ql_rc = ql.CashFlows.yieldRate(BondLeg, dirty_val, ql.Actual365Fixed(), ql.Compounded, ql.Continuous, True)

应该是:

ql_rc = ql.CashFlows.yieldRate(BondLeg, dirty_val, ql.Actual365Fixed(), ql.Continuous, ql.NoFrequency, True)

也就是说,

ql.Continuous
不是与
ql.Compounded
关联的频率,而是其本身的复合方法。第二次调用给出了您期望的结果。

不幸的是,SWIG 将 C++ 枚举导出为没有特定类型的数值常量,因此 Python 无法警告不匹配情况。第一个调用将

ql.Continuous
的数值 2 解释为半年复利频率。

© www.soinside.com 2019 - 2024. All rights reserved.