Posted by
aexhg on
URL: http://quantlib.414.s1.nabble.com/qunatlib-us-treasury-true-yield-tp8100p8101.html
Hi,
Here's an example for two treasury bonds. The difference between the yields is small but this can have a larger impact on the risk calcualtion.
#include <iostream>
#include <ql\quantlib.hpp>
#include <string>
#include <boost\function.hpp>
#include <boost\bind.hpp>
using namespace QuantLib;
Real treasuryDirtyPrice(const Bond & bond, const Date & settlementDate,Real yield)
{
Leg leg = bond.cashflows();
Real npv = 0.0;
Real discount = 1.0;
Date lastDate = settlementDate;
Integer n = leg.size();
for(Integer i = 0; i < n; ++i)
{
boost::shared_ptr<CashFlow> cf = leg[i];
Date paydate = cf->date();
if(paydate > settlementDate)
{
Real amount = cf->amount();
if(i != n - 1)
{
boost::shared_ptr<FixedRateCoupon> coupon = boost::dynamic_pointer_cast<FixedRateCoupon>(cf);
if(cf)
{
Date accStart = coupon->accrualStartDate();
Date accEnd = coupon->accrualEndDate();
DayCounter dc = coupon->dayCounter();
Real tau = dc.yearFraction(lastDate,paydate,accStart,accEnd);
discount *= 1.0 / std::pow(( 1.0 + yield *0.5) ,tau * 2.0);
lastDate = paydate;
}
}
npv += discount * amount;
}
}
return npv / bond.notional(settlementDate) * 100.0;
}
Real objFunc(const Bond & bond, const Date & settlementDate, Real mktDirtyPrice, Real yield)
{
return mktDirtyPrice - treasuryDirtyPrice(bond,settlementDate,yield);
}
Real semiAnnualTreasuryYield(const Bond & bond, const Date & settlementDate, Real cleanPrice)
{
Real dirtyPrice = cleanPrice + bond.accruedAmount(settlementDate);
Secant solver;
boost::function<Real (Real)> f(boost::bind(objFunc,bond,settlementDate,dirtyPrice,_1));
solver.setMaxEvaluations(100);
return solver.solve(f, 1E-10, 0.05,0.005);
}
int main() {
const int nBonds = 2;
const std::string isins [] = { "US912810FB99" , "US912828TN08"};
const Date issueDates [] = { Date(17,Nov,1997) , Date(31,Aug,2012) };
const Date maturityDates [] = { Date(15,Nov,2027) , Date(31,Aug,2019) };
const Date firstCouponDates [] = { Date(15,May,1998) , Date(31,Aug,2012) };
const Integer eom [] = {0, 1};
const Real coupons [] = { 0.06125 , 0.01};
const Real mktPrices [] = { 149.703125,99.199853 };
const Real streetYields [] = { 2.2194243 , 1.220000};
const Real trueYields [] = { 2.2193023 , 1.120670 };
Calendar calendar = UnitedStates(UnitedStates::GovernmentBond);
DayCounter dayCounter = ActualActual(ActualActual::ISMA);
Date today = Date(31,Oct,2012);
Date settle = calendar.advance(today,1,Days);
std::cout << std::setw(15) << "Bond ISIN" << "|"
<< std::setw(12) << "QL Yield" << "|"
<< std::setw(12) << "my Yield" << "|"
<< std::setw(12) << "str. Yield" << "|"
<< std:: setw(12)<< "true Yield" << "|"
<< std::endl;
for(int i = 0; i < nBonds; ++i)
{
Schedule sched = Schedule(issueDates[i],maturityDates[i],Period(6,TimeUnit::Months),calendar,
Unadjusted,Unadjusted,DateGeneration::Backward,eom[i],firstCouponDates[i]);
FixedRateBond bond(1,100.0,sched,std::vector<Rate>(1,coupons[i]),
dayCounter,Following,100.0,
issueDates[i],calendar);
Real yld = BondFunctions::yield(bond,mktPrices[i],dayCounter,Compounded,Semiannual,settle) * 100.0;
Real myyld = semiAnnualTreasuryYield(bond,settle,mktPrices[i]) * 100.0;
Real streetYld = streetYields[i];
Real trueYld = trueYields[i];
std::cout<< std::setw(15) << isins[i] << "|"
<< std::setw(12) << yld << std::setprecision(8) << "|"
<< std::setw(12) << myyld << std::setprecision(8) << "|"
<< std::setw(12) << streetYld << std::setprecision(8) << "|"
<< std::setw(12) << trueYld << std::setprecision(8) << "|"
<< std::endl;
}
std::cin.get();
return 0;
}
and the output I get is:
Bond ISIN| QL Yield| my Yield| str. Yield| true Yield|
US912810FB99| 2.21942| 2.2193023| 2.2194243| 2.2193023|
US912828TN08| 1.1219999| 1.120655| 1.22| 1.12067|
Thanks.
aexhg wrote
Hi,
I'm trying to match up the true yield calculation of us treasury (bbg) with quantlib. It seems to me that the cashflows::npv() does not take into account the coupon referencePeriodBegin & referencePeriodEnd, so for us treasuries with bad days, specifying a daycount convention of ISMA, I'll never quite match the quoted bbg yield. I was just wondering if I'm missing something or if there's a workaround?