C++ Quantlib解算器的到期收益率与BondFunctions::yield不同
我想完全理解Quantlib的解算器是如何在给定预测期限结构和贴现期限结构的情况下计算浮动利率债券的Z价差的。为此,首先我创建了一个简单的辅助类来计算债券的到期收益率,我将与解算器(我选择了Brent)一起使用它来比较收益率计算与BondFunctions::yield。尽管如此,对于三个样本债券,我得到了两个不同的结果,我不明白为什么 首先,我创建一个辅助类,使用quantlib的解算器数值计算债券的到期收益率C++ Quantlib解算器的到期收益率与BondFunctions::yield不同,c++,yield,solver,quantlib,C++,Yield,Solver,Quantlib,我想完全理解Quantlib的解算器是如何在给定预测期限结构和贴现期限结构的情况下计算浮动利率债券的Z价差的。为此,首先我创建了一个简单的辅助类来计算债券的到期收益率,我将与解算器(我选择了Brent)一起使用它来比较收益率计算与BondFunctions::yield。尽管如此,对于三个样本债券,我得到了两个不同的结果,我不明白为什么 首先,我创建一个辅助类,使用quantlib的解算器数值计算债券的到期收益率 class ytmsolver{ private: const Real
class ytmsolver{
private:
const Real obsPrice;
const Bond& bondObject;
const Date& date;
DayCounter dayCounter;
Compounding compounding;
Frequency frequency;
public:
//constructor
ytmsolver(const Bond &bond, Real &price, Date &settlementDate, DayCounter& dc, Compounding& comp,
Frequency& freq):bondObject(bond),obsPrice(price),date(settlementDate), dayCounter(dc),
compounding(comp),frequency(freq){};
//overloaded operator to be used in the solver
Real operator()(const Rate& rate)const{
return (bondObject.cleanPrice(rate,dayCounter,compounding,frequency)-obsPrice);
}
})
然后,我创建了一个浮动利率债券工厂,它创建了一个带有指数的浮动利率,一个预测期限结构(为了简化目前的计算,假设是平的)和一个定价引擎
FloatingRateBond flatTermStructureFloaterFactory(Natural indexTenor, Frequency freq, Date tradeDate,
Date settlementDate,Natural settlementDays, Real faceAmount, const Schedule &schedule,
const Calendar& calendar,const Real ¤tLiborFixing,const Real& lastResetDateLiborFixing,
const DayCounter &accrualDayCounter,
BusinessDayConvention paymentConvention=Following, Natural fixingDays=Null< Natural >(),
const std::vector< Real > &gearings=std::vector< Real >(1, 1.0),
const std::vector< Spread > &spreads=std::vector< Spread >(1, 0.0),
const std::vector< Rate > &caps=std::vector< Rate >(),
const std::vector< Rate > &floors=std::vector< Rate >(),
bool inArrears=false, Real redemption=100.0, const Date &issueDate=Date()){
//***********Term structure declaration***********
//term structure for the cash flows using a libor index
RelinkableHandle<YieldTermStructure> liborTermStructure;
//Libor index which is tied to the Frequency of payments or index tenor
boost::shared_ptr<IborIndex> libor(new USDLibor(Period(indexTenor,Months),liborTermStructure));
//term structure to forecast rest of cash flows
boost::shared_ptr<YieldTermStructure> flatforecast(
new FlatForward(settlementDate, currentLiborFixing, accrualDayCounter, Simple, freq));
liborTermStructure.linkTo(flatforecast);
//Relinkable handle to assign to the price engine.
RelinkableHandle<YieldTermStructure> discountingTermStructure;
//***********Bond object creation***********
FloatingRateBond floatingRateBondInstance(settlementDays, faceAmount,
schedule, libor, accrualDayCounter,
paymentConvention, fixingDays,
// gearings
gearings,
// spreads
spreads);
//*********Finds the last reset date****************
Date lastResetDate;
Leg cashflows=floatingRateBondInstance.cashflows();
/*
Finds the last reset date by browsing through the cashflow dates and offsetting them by
the number of fixing days and a provided calendar.
(ONLY WORKS WITH BONDS WITH THE SAME INDEX AS PERIODICITY)
If this date is provided by the flat file then this search is completely unnecessary
*/
for (Size i=0; i<cashflows.size()-1; i++) {
//Takes the lastResetDate to be the las ocurred date prior the the tradeDate
if ((cashflows[i]->hasOccurred(tradeDate, true))) {
lastResetDate=calendar.advance(cashflows[i]->date(),-fixingDays, Days,paymentConvention);
//cout<<lastResetDate<<endl; //used to print the dates as a debug method.
}
}
cout<<"lastResetDate: "<<lastResetDate<<endl; //prints it to ensure that its correct.
//*********Adds the previous libor rate associated to the last reset date*************
libor->addFixing(lastResetDate, lastResetDateLiborFixing); //last reset date minus fixing days
//***********Bond Engine declaration***********
boost::shared_ptr<PricingEngine> bondEngine(new DiscountingBondEngine (discountingTermStructure));
floatingRateBondInstance.setPricingEngine(bondEngine); //setting the pricing engine for the bond
return floatingRateBondInstance;
}
然后我尝试使用Quantlib的解算器,得到这些债券的收益率,给出一个干净的价格,我使用以下代码得到不同的结果:
int main(){
try {
Brent solver;
Real accuracy=1e-30, guess=0.00, min=-1.0, max=0.5;
cout<<"*******************************************"<<endl;
cout<<"Bond # 1: US4042Q0HC65"<<endl;
cout<<"*******************************************"<<endl;
//***********Input declaration***********
Natural settlementDays = 3;
Natural fixingdays=2;
Natural indexTenor=6;
Date tradeDate(02,Mar,2015);
Date issueDate(9,Aug,2006);
Date maturityDate(22,Aug,2016);
Real resetMargin=0.016;
Real indexMultiplier=1.0;
Frequency frequency=Semiannual;
Calendar holidayCalendar=UnitedStates(UnitedStates::NYSE);
BusinessDayConvention businessDayConvention= BusinessDayConvention(ModifiedFollowing);
DayCounter dayCounter=Actual360();
Real lastResetDateLiborFixing=0.003853;
Real currentLiborFixing=0.003842;
Real redemption=100;
string settlementcode="BDY"; //internal settlementcode
string settlementvalue="3"; //internal settlementvalue
Date settlementDate=getSettlementDate(tradeDate,holidayCalendar,settlementcode,settlementvalue); //function call to get the settlement date (this is working properly)
cout<<"settlementDate :"<<settlementDate<<endl;
Compounding compounding=Compounded;
Real faceAmount = redemption;
Real obsprice=101.431;
Schedule schedule(issueDate, maturityDate, Period(frequency),
holidayCalendar, businessDayConvention, businessDayConvention,
DateGeneration::Backward, true);
//***********Bond creation to be priced***********
FloatingRateBond floatingRateBondInstance1=flatTermStructureFloaterFactory(indexTenor,frequency,tradeDate,settlementDate,
settlementDays,faceAmount,schedule,holidayCalendar,currentLiborFixing,lastResetDateLiborFixing,
dayCounter,businessDayConvention,fixingdays,std::vector<Real>(1, indexMultiplier),
std::vector<Rate>(1, resetMargin));
Real ytm=priceToYieldFlatTermStructure(floatingRateBondInstance1,obsprice,dayCounter,compounding,frequency,settlementDate);
//***********Bond pricing, yield and discount marging computation***********
cout<<"Clean price: "<<floatingRateBondInstance1.cleanPrice(ytm,dayCounter,compounding,frequency,settlementDate)<<endl;
cout<<"Dirty price: "<<floatingRateBondInstance1.dirtyPrice(ytm,dayCounter,compounding,frequency,settlementDate)<<endl;
cout<<"Accrued interest: "<<floatingRateBondInstance1.accruedAmount(settlementDate)<<endl;
cout<<"Yield: "<<ytm*100<<"%"<<endl;
cout<<"Discount Margin: "<<(ytm-currentLiborFixing)*100<<"%"<<endl;
//***************solver testing***************
Real irr=solver.solve(ytmsolver(floatingRateBondInstance1,obsprice,settlementDate,dayCounter,
compounding,frequency),accuracy,guess,min,max);
cout<<"irr: "<<irr*100<<"%"<<endl;
cout<<"*******************************************"<<endl;
cout<<"Bond # 2: US4042Q0HB82"<<endl;
cout<<"*******************************************"<<endl;
//***********Input declaration***********
indexTenor=6;
issueDate=Date(27,Jul,2006);
maturityDate=Date(20,Jul,2016);
resetMargin=0.0151;
indexMultiplier=1.0;
frequency=Semiannual;
holidayCalendar=TARGET();
//holidayCalendar=UnitedStates(UnitedStates::NYSE); //not counting martin luther king day, jan 15,15 as last reset date
businessDayConvention=BusinessDayConvention(ModifiedFollowing);
dayCounter=Actual360();
lastResetDateLiborFixing=0.003549;
currentLiborFixing=0.003842;
redemption=100;
settlementcode="BDY"; //internal settlement code
settlementvalue="3"; //internal settlement value
settlementDate=getSettlementDate(tradeDate,holidayCalendar,settlementcode,settlementvalue); //function call to get the settlement date (this is working properly)
cout<<"settlementDate :"<<settlementDate<<endl;
compounding=Compounded;
faceAmount = redemption;
obsprice=100.429;
schedule=Schedule(issueDate, maturityDate, Period(frequency),
holidayCalendar, businessDayConvention, businessDayConvention,
DateGeneration::Backward, true);
//***********Bond creation to be priced***********
FloatingRateBond floatingRateBondInstance2=flatTermStructureFloaterFactory(indexTenor,frequency,tradeDate,settlementDate,
settlementDays,faceAmount,schedule,holidayCalendar,currentLiborFixing,lastResetDateLiborFixing,
dayCounter,businessDayConvention,fixingdays,std::vector<Real>(1, indexMultiplier),
std::vector<Rate>(1, resetMargin));
ytm=priceToYieldFlatTermStructure(floatingRateBondInstance2,obsprice,dayCounter,compounding,frequency,settlementDate);
//***********Bond pricing, yield and discount marging computation***********
cout<<"Clean price: "<<floatingRateBondInstance2.cleanPrice(ytm,dayCounter,compounding,frequency,settlementDate)<<endl;
cout<<"Dirty price: "<<floatingRateBondInstance2.dirtyPrice(ytm,dayCounter,compounding,frequency,settlementDate)<<endl;
cout<<"Accrued interest: "<<floatingRateBondInstance2.accruedAmount(settlementDate)<<endl;
cout<<"Yield: "<<ytm*100<<"%"<<endl;
cout<<"Discount Margin: "<<(ytm-currentLiborFixing)*100<<"%"<<endl;
//***************solver testing***************
irr=solver.solve(ytmsolver(floatingRateBondInstance2,obsprice,settlementDate,dayCounter,
compounding,frequency),accuracy,guess,min,max);
cout<<"irr: "<<irr*100<<"%"<<endl;
cout<<"*******************************************"<<endl;
cout<<"Bond # 3: US59022CCT80"<<endl;
cout<<"*******************************************"<<endl;
//***********Input declaration***********
indexTenor=3;
tradeDate=Date(10,Jun,2015);
issueDate=Date(02,May,2007);
maturityDate=Date(02,May,2017);
resetMargin=0.0055;
indexMultiplier=1.0;
frequency=Quarterly;
holidayCalendar=UnitedStates(UnitedStates::NYSE); //not counting martin luther kind day, jan 15,15 as last reset date
businessDayConvention=BusinessDayConvention(ModifiedFollowing);
dayCounter=Actual360();
lastResetDateLiborFixing=0.0027875;
currentLiborFixing=0.0028785;
redemption=100;
settlementcode="BDY"; //internal settlement code
settlementvalue="3"; //internal settlement value
settlementDate=getSettlementDate(tradeDate,holidayCalendar,settlementcode,settlementvalue); //function call to get the settlement date (this is working properly)
cout<<"settlementDate :"<<settlementDate<<endl;
compounding=Compounded;
faceAmount = redemption;
obsprice=99.794;
schedule=Schedule(issueDate, maturityDate, Period(frequency),
holidayCalendar, businessDayConvention, businessDayConvention,
DateGeneration::Backward, true);
//***********Bond pricing, yield and discount marging computation***********
FloatingRateBond floatingRateBondInstance3=flatTermStructureFloaterFactory(indexTenor,frequency,tradeDate,settlementDate,
settlementDays,faceAmount,schedule,holidayCalendar,currentLiborFixing,lastResetDateLiborFixing,
dayCounter,businessDayConvention,fixingdays,std::vector<Real>(1, indexMultiplier),
std::vector<Rate>(1, resetMargin));
ytm=priceToYieldFlatTermStructure(floatingRateBondInstance3,obsprice,dayCounter,compounding,frequency,settlementDate);
//***********Bond pricing, yield and discount marging computation***********
cout<<"Clean price: "<<floatingRateBondInstance3.cleanPrice(ytm,dayCounter,compounding,frequency,settlementDate)<<endl;
cout<<"Dirty price: "<<floatingRateBondInstance3.dirtyPrice(ytm,dayCounter,compounding,frequency,settlementDate)<<endl;
cout<<"Accrued interest: "<<floatingRateBondInstance3.accruedAmount(settlementDate)<<endl;
cout<<"Yield: "<<ytm*100<<"%"<<endl;
cout<<"Discount Margin: "<<(ytm-currentLiborFixing)*100<<"%"<<endl;
//***************solver testing***************
irr=solver.solve(ytmsolver(floatingRateBondInstance3,obsprice,settlementDate,dayCounter,
compounding,frequency),accuracy,guess,min,max);
cout<<"irr: "<<irr*100<<"%"<<endl;
return 0;
} catch (exception& e) {
cerr << e.what() << endl;
return 1;
} catch (...) {
cerr << "unknown error" << endl;
return 1;
}
intmain(){
试一试{
布伦特解算器;
实际精度=1e-30,猜测=0.00,最小值=-1.0,最大值=0.5;
cout我将假设收益率返回的QuantLibBondFunctions::yield
函数是正确的,因为当您将其传递给债券的cleanPrice
方法时,您会得到用作输入的观察价格
这让我们可以猜测您的函数有什么问题。通过查看您的ytmsolver
类,我注意到您没有将结算日期传递给债券对象的cleanPrice
方法,就像您在重新定价代码时在main
中所做的那样
当结算日期缺失时,该方法假设它是今天的结算日期,即从今天起三个工作日。这明显晚于您想要的结算日期以及您在main
函数中输出的结算日期,因此您会得到错误的收益率。一旦您将结算日期传递给cleanPrice
,解算器返回预期值
int main(){
try {
Brent solver;
Real accuracy=1e-30, guess=0.00, min=-1.0, max=0.5;
cout<<"*******************************************"<<endl;
cout<<"Bond # 1: US4042Q0HC65"<<endl;
cout<<"*******************************************"<<endl;
//***********Input declaration***********
Natural settlementDays = 3;
Natural fixingdays=2;
Natural indexTenor=6;
Date tradeDate(02,Mar,2015);
Date issueDate(9,Aug,2006);
Date maturityDate(22,Aug,2016);
Real resetMargin=0.016;
Real indexMultiplier=1.0;
Frequency frequency=Semiannual;
Calendar holidayCalendar=UnitedStates(UnitedStates::NYSE);
BusinessDayConvention businessDayConvention= BusinessDayConvention(ModifiedFollowing);
DayCounter dayCounter=Actual360();
Real lastResetDateLiborFixing=0.003853;
Real currentLiborFixing=0.003842;
Real redemption=100;
string settlementcode="BDY"; //internal settlementcode
string settlementvalue="3"; //internal settlementvalue
Date settlementDate=getSettlementDate(tradeDate,holidayCalendar,settlementcode,settlementvalue); //function call to get the settlement date (this is working properly)
cout<<"settlementDate :"<<settlementDate<<endl;
Compounding compounding=Compounded;
Real faceAmount = redemption;
Real obsprice=101.431;
Schedule schedule(issueDate, maturityDate, Period(frequency),
holidayCalendar, businessDayConvention, businessDayConvention,
DateGeneration::Backward, true);
//***********Bond creation to be priced***********
FloatingRateBond floatingRateBondInstance1=flatTermStructureFloaterFactory(indexTenor,frequency,tradeDate,settlementDate,
settlementDays,faceAmount,schedule,holidayCalendar,currentLiborFixing,lastResetDateLiborFixing,
dayCounter,businessDayConvention,fixingdays,std::vector<Real>(1, indexMultiplier),
std::vector<Rate>(1, resetMargin));
Real ytm=priceToYieldFlatTermStructure(floatingRateBondInstance1,obsprice,dayCounter,compounding,frequency,settlementDate);
//***********Bond pricing, yield and discount marging computation***********
cout<<"Clean price: "<<floatingRateBondInstance1.cleanPrice(ytm,dayCounter,compounding,frequency,settlementDate)<<endl;
cout<<"Dirty price: "<<floatingRateBondInstance1.dirtyPrice(ytm,dayCounter,compounding,frequency,settlementDate)<<endl;
cout<<"Accrued interest: "<<floatingRateBondInstance1.accruedAmount(settlementDate)<<endl;
cout<<"Yield: "<<ytm*100<<"%"<<endl;
cout<<"Discount Margin: "<<(ytm-currentLiborFixing)*100<<"%"<<endl;
//***************solver testing***************
Real irr=solver.solve(ytmsolver(floatingRateBondInstance1,obsprice,settlementDate,dayCounter,
compounding,frequency),accuracy,guess,min,max);
cout<<"irr: "<<irr*100<<"%"<<endl;
cout<<"*******************************************"<<endl;
cout<<"Bond # 2: US4042Q0HB82"<<endl;
cout<<"*******************************************"<<endl;
//***********Input declaration***********
indexTenor=6;
issueDate=Date(27,Jul,2006);
maturityDate=Date(20,Jul,2016);
resetMargin=0.0151;
indexMultiplier=1.0;
frequency=Semiannual;
holidayCalendar=TARGET();
//holidayCalendar=UnitedStates(UnitedStates::NYSE); //not counting martin luther king day, jan 15,15 as last reset date
businessDayConvention=BusinessDayConvention(ModifiedFollowing);
dayCounter=Actual360();
lastResetDateLiborFixing=0.003549;
currentLiborFixing=0.003842;
redemption=100;
settlementcode="BDY"; //internal settlement code
settlementvalue="3"; //internal settlement value
settlementDate=getSettlementDate(tradeDate,holidayCalendar,settlementcode,settlementvalue); //function call to get the settlement date (this is working properly)
cout<<"settlementDate :"<<settlementDate<<endl;
compounding=Compounded;
faceAmount = redemption;
obsprice=100.429;
schedule=Schedule(issueDate, maturityDate, Period(frequency),
holidayCalendar, businessDayConvention, businessDayConvention,
DateGeneration::Backward, true);
//***********Bond creation to be priced***********
FloatingRateBond floatingRateBondInstance2=flatTermStructureFloaterFactory(indexTenor,frequency,tradeDate,settlementDate,
settlementDays,faceAmount,schedule,holidayCalendar,currentLiborFixing,lastResetDateLiborFixing,
dayCounter,businessDayConvention,fixingdays,std::vector<Real>(1, indexMultiplier),
std::vector<Rate>(1, resetMargin));
ytm=priceToYieldFlatTermStructure(floatingRateBondInstance2,obsprice,dayCounter,compounding,frequency,settlementDate);
//***********Bond pricing, yield and discount marging computation***********
cout<<"Clean price: "<<floatingRateBondInstance2.cleanPrice(ytm,dayCounter,compounding,frequency,settlementDate)<<endl;
cout<<"Dirty price: "<<floatingRateBondInstance2.dirtyPrice(ytm,dayCounter,compounding,frequency,settlementDate)<<endl;
cout<<"Accrued interest: "<<floatingRateBondInstance2.accruedAmount(settlementDate)<<endl;
cout<<"Yield: "<<ytm*100<<"%"<<endl;
cout<<"Discount Margin: "<<(ytm-currentLiborFixing)*100<<"%"<<endl;
//***************solver testing***************
irr=solver.solve(ytmsolver(floatingRateBondInstance2,obsprice,settlementDate,dayCounter,
compounding,frequency),accuracy,guess,min,max);
cout<<"irr: "<<irr*100<<"%"<<endl;
cout<<"*******************************************"<<endl;
cout<<"Bond # 3: US59022CCT80"<<endl;
cout<<"*******************************************"<<endl;
//***********Input declaration***********
indexTenor=3;
tradeDate=Date(10,Jun,2015);
issueDate=Date(02,May,2007);
maturityDate=Date(02,May,2017);
resetMargin=0.0055;
indexMultiplier=1.0;
frequency=Quarterly;
holidayCalendar=UnitedStates(UnitedStates::NYSE); //not counting martin luther kind day, jan 15,15 as last reset date
businessDayConvention=BusinessDayConvention(ModifiedFollowing);
dayCounter=Actual360();
lastResetDateLiborFixing=0.0027875;
currentLiborFixing=0.0028785;
redemption=100;
settlementcode="BDY"; //internal settlement code
settlementvalue="3"; //internal settlement value
settlementDate=getSettlementDate(tradeDate,holidayCalendar,settlementcode,settlementvalue); //function call to get the settlement date (this is working properly)
cout<<"settlementDate :"<<settlementDate<<endl;
compounding=Compounded;
faceAmount = redemption;
obsprice=99.794;
schedule=Schedule(issueDate, maturityDate, Period(frequency),
holidayCalendar, businessDayConvention, businessDayConvention,
DateGeneration::Backward, true);
//***********Bond pricing, yield and discount marging computation***********
FloatingRateBond floatingRateBondInstance3=flatTermStructureFloaterFactory(indexTenor,frequency,tradeDate,settlementDate,
settlementDays,faceAmount,schedule,holidayCalendar,currentLiborFixing,lastResetDateLiborFixing,
dayCounter,businessDayConvention,fixingdays,std::vector<Real>(1, indexMultiplier),
std::vector<Rate>(1, resetMargin));
ytm=priceToYieldFlatTermStructure(floatingRateBondInstance3,obsprice,dayCounter,compounding,frequency,settlementDate);
//***********Bond pricing, yield and discount marging computation***********
cout<<"Clean price: "<<floatingRateBondInstance3.cleanPrice(ytm,dayCounter,compounding,frequency,settlementDate)<<endl;
cout<<"Dirty price: "<<floatingRateBondInstance3.dirtyPrice(ytm,dayCounter,compounding,frequency,settlementDate)<<endl;
cout<<"Accrued interest: "<<floatingRateBondInstance3.accruedAmount(settlementDate)<<endl;
cout<<"Yield: "<<ytm*100<<"%"<<endl;
cout<<"Discount Margin: "<<(ytm-currentLiborFixing)*100<<"%"<<endl;
//***************solver testing***************
irr=solver.solve(ytmsolver(floatingRateBondInstance3,obsprice,settlementDate,dayCounter,
compounding,frequency),accuracy,guess,min,max);
cout<<"irr: "<<irr*100<<"%"<<endl;
return 0;
} catch (exception& e) {
cerr << e.what() << endl;
return 1;
} catch (...) {
cerr << "unknown error" << endl;
return 1;
}