Hello all!
Just started with QuantLib recently and am particularly interested in
building yield curves and pricing bonds from the created curves.
As a start, I modified the FittedBondCurve example so that the inputs match
the 6 on the run US Treasury bonds (2, 3, 5, 7, 10 and 30 year). This
example creates 6 yield curves, 5 of them using the FittedBondDiscountCurve
and 1 using PiecewiseYieldCurve.
After creating the curves, I set the curve as the bondPricingEngine and then
priced the input bond from that curve. These results deviate significantly
more from my inputs than I expected, so I suspect I may have done something
wrong.
In yield space, the Nelson-Siegel curve has theoretical yields between 10-40
bp different than my input bonds. Is this expected? If not, could someone
please take a look at my code and see what mistake I may have made?
Thank you!
int main(int, char* []) {
try {
boost::timer timer;
const Size numberOfBonds = 6;
Real cleanPrice[] = {99.884973, 99.785254, 99.868202, 100.084135,
99.677148, 99.376953};
std::vector< boost::shared_ptr<SimpleQuote> > quote;
for (Size i=0; i<numberOfBonds; i++) {
boost::shared_ptr<SimpleQuote> cp(new
SimpleQuote(cleanPrice[i]));
quote.push_back(cp);
}
RelinkableHandle quoteHandle[numberOfBonds];
for (Size i=0; i<numberOfBonds; i++) {
quoteHandle[i].linkTo(quote[i]);
}
Real coupons[] = { 0.01, 0.0125, 0.0175, 0.02125, 0.0225, 0.03};
Date maturities[] = {Date(31,December,2017), Date(15,December,2018),
Date(31,December,2020), Date(31,December,2022), Date(15,November,2025),
Date(15,November,2045)};
Frequency frequency = Semiannual;
DayCounter dc = ActualActual(ActualActual::Bond);
BusinessDayConvention accrualConvention = Following;
BusinessDayConvention convention = Following;
Real redemptionAmount = 100.0;
Real faceAmount = 100.0;
Calendar calendar = UnitedStates(UnitedStates::GovernmentBond);
Date evaluationDay = Date(31,December,2015);
Settings::instance().evaluationDate() = evaluationDay;
Natural bondSettlementDays = 1;
Natural curveSettlementDays = 1;
Date bondSettlementDate = calendar.advance(evaluationDay,
bondSettlementDays*Days);
cout << endl;
cout << "EvaluationDay: " << evaluationDay
<< endl;
cout << "Bonds' settlement date: " <<
bondSettlementDate << endl;
cout << "Calculating fit for 6 bonds....." <<
endl << endl;
std::vector<boost::shared_ptr<BondHelper> > instrumentsA;
std::vector<boost::shared_ptr<RateHelper> > instrumentsB;
for (Size j=0; j<LENGTH(coupons); j++) {
Schedule schedule(bondSettlementDate, maturities[j],
Period(frequency),
calendar, accrualConvention,
accrualConvention,
DateGeneration::Backward, true);
boost::shared_ptr<BondHelper> helperA(
new FixedRateBondHelper(quoteHandle[j],
bondSettlementDays,
faceAmount,
schedule,
std::vector<Rate>(1,coupons[j]),
dc,
convention,
redemptionAmount));
boost::shared_ptr<RateHelper> helperB(
new FixedRateBondHelper(quoteHandle[j],
bondSettlementDays,
faceAmount,
schedule,
std::vector<Rate>(1,
coupons[j]),
dc,
convention,
redemptionAmount));
instrumentsA.push_back(helperA);
instrumentsB.push_back(helperB);
}
bool constrainAtZero = true;
Real tolerance = 1.0e-10;
Size max = 5000;
boost::shared_ptr<YieldTermStructure> ts0 (
new
PiecewiseYieldCurve<Discount,LogLinear>(curveSettlementDays,
calendar,
instrumentsB,
dc));
ExponentialSplinesFitting exponentialSplines(constrainAtZero);
boost::shared_ptr<FittedBondDiscountCurve> ts1 (
new FittedBondDiscountCurve(curveSettlementDays,
calendar,
instrumentsA,
dc,
exponentialSplines,
tolerance,
max));
printOutput("(a) exponential splines", ts1);
SimplePolynomialFitting simplePolynomial(3, constrainAtZero);
boost::shared_ptr<FittedBondDiscountCurve> ts2 (
new FittedBondDiscountCurve(curveSettlementDays,
calendar,
instrumentsA,
dc,
simplePolynomial,
tolerance,
max));
printOutput("(b) simple polynomial", ts2);
NelsonSiegelFitting nelsonSiegel;
boost::shared_ptr<FittedBondDiscountCurve> ts3 (
new FittedBondDiscountCurve(curveSettlementDays,
calendar,
instrumentsA,
dc,
nelsonSiegel,
tolerance,
max));
printOutput("(c) Nelson-Siegel", ts3);
// a cubic bspline curve with 11 knot points, implies
// n=6 (constrained problem) basis functions
Time knots[] = { -30.0, -20.0, 0.0, 5.0, 10.0, 15.0,
20.0, 25.0, 30.0, 40.0, 50.0 };
std::vector<Time> knotVector;
for (Size i=0; i< LENGTH(knots); i++) {
knotVector.push_back(knots[i]);
}
CubicBSplinesFitting cubicBSplines(knotVector, constrainAtZero);
boost::shared_ptr<FittedBondDiscountCurve> ts4 (
new FittedBondDiscountCurve(curveSettlementDays,
calendar,
instrumentsA,
dc,
cubicBSplines,
tolerance,
max));
printOutput("(d) cubic B-splines", ts4);
SvenssonFitting svensson;
boost::shared_ptr<FittedBondDiscountCurve> ts5 (
new FittedBondDiscountCurve(curveSettlementDays,
calendar,
instrumentsA,
dc,
svensson,
tolerance,
max));
printOutput("(e) Svensson", ts5);
cout << "Output Yield and basis point difference for each curve. In
this case, "
<< endl
//<< "par rates should equal coupons for these par bonds."
<< endl
<< endl;
cout << setw(6) << "tenor" << " | "
<< setw(6) << "coupon" << " | "
<< setw(6) << "Yield" << " | "
<< setw(6) << "(btstrp)" << "|"
<< setw(6) << "(exp spl)" << "|"
<< setw(6) << "(s poly)" << "|"
<< setw(6) << "(Nel-Sie)" << "|"
<< setw(6) << "(CubBSpl)" << "|"
<< setw(6) << "(Svensson)" << endl;
for (Size i=0; i<instrumentsA.size(); i++) {
std::vector<boost::shared_ptr<CashFlow> > cfs =
instrumentsA[i]->bond()->cashflows();
Size cfSize = instrumentsA[i]->bond()->cashflows().size();
std::vector<Date> keyDates;
keyDates.push_back(bondSettlementDate);
for (Size j=0; j<cfSize-1; j++) {
if (!cfs[j]->hasOccurred(bondSettlementDate, false)) {
Date myDate = cfs[j]->date();
keyDates.push_back(myDate);
}
}
Real tenor = dc.yearFraction(evaluationDay,
cfs[cfSize-1]->date());
boost::shared_ptr< Bond > fixedRateBond =
instrumentsA[i]->bond();
boost::shared_ptr<PricingEngine> ts0BondEngine(new
DiscountingBondEngine(Handle<YieldTermStructure>(ts0)));
boost::shared_ptr<PricingEngine> ts1BondEngine(new
DiscountingBondEngine(Handle<YieldTermStructure>(ts1)));
boost::shared_ptr<PricingEngine> ts2BondEngine(new
DiscountingBondEngine(Handle<YieldTermStructure>(ts2)));
boost::shared_ptr<PricingEngine> ts3BondEngine(new
DiscountingBondEngine(Handle<YieldTermStructure>(ts3)));
boost::shared_ptr<PricingEngine> ts4BondEngine(new
DiscountingBondEngine(Handle<YieldTermStructure>(ts4)));
boost::shared_ptr<PricingEngine> ts5BondEngine(new
DiscountingBondEngine(Handle<YieldTermStructure>(ts5)));
Real inputYield = fixedRateBond->yield(cleanPrice[i], dc,
Simple, frequency, bondSettlementDate);
fixedRateBond->setPricingEngine(ts0BondEngine);
Real ts0Price = fixedRateBond->cleanPrice();
Real yieldts0 = fixedRateBond->yield(ts0Price, dc, Simple,
frequency, bondSettlementDate);
fixedRateBond->setPricingEngine(ts1BondEngine);
Real ts1Price = fixedRateBond->cleanPrice();
Real yieldts1 = fixedRateBond->yield(ts1Price, dc, Simple,
frequency, bondSettlementDate);
fixedRateBond->setPricingEngine(ts2BondEngine);
Real ts2Price = fixedRateBond->cleanPrice();
Real yieldts2 = fixedRateBond->yield(ts2Price, dc, Simple,
frequency, bondSettlementDate);
fixedRateBond->setPricingEngine(ts3BondEngine);
Real ts3Price = fixedRateBond->cleanPrice();
Real yieldts3 = fixedRateBond->yield(ts3Price, dc, Simple,
frequency, bondSettlementDate);
fixedRateBond->setPricingEngine(ts4BondEngine);
Real ts4Price = fixedRateBond->cleanPrice();
Real yieldts4 = fixedRateBond->yield(ts4Price, dc, Simple,
frequency, bondSettlementDate);
fixedRateBond->setPricingEngine(ts5BondEngine);
Real ts5Price = fixedRateBond->cleanPrice();
Real yieldts5 = fixedRateBond->yield(ts5Price, dc, Simple,
frequency, bondSettlementDate);
cout << setw(6) << fixed << setprecision(3) << tenor << " | "
<< setw(6) << fixed << setprecision(3)
<< 100.*coupons[i] << " | "
<< setw(6) << fixed << setprecision(6)
<< inputYield << " | "
// piecewise bootstrap
<< setw(6) << fixed << setprecision(3)
<< (yieldts0 - inputYield)*10000 << " | "
// exponential splines
<< setw(6) << fixed << setprecision(3)
<< (yieldts1 - inputYield)*10000 << " | "
// simple polynomial
<< setw(6) << fixed << setprecision(3)
<< (yieldts2 - inputYield)*10000 << " | "
// Nelson-Siegel
<< setw(6) << fixed << setprecision(3)
<< (yieldts3 - inputYield)*10000<< " | "
// cubic bsplines
<< setw(6) << fixed << setprecision(3)
<< (yieldts4 - inputYield)*10000 << " | "
// Svensson
<< setw(6) << fixed << setprecision(3)
<< (yieldts5 - inputYield)*10000 << endl;
}
return(0);
} catch (std::exception& e) {
cerr << e.what() << endl;
return 1;
} catch (...) {
cerr << "unknown error" << endl;
return 1;
}
:::Output:::
EvaluationDay: December 31st, 2015
Bonds' settlement date: January 4th, 2016
Calculating fit for 6 bonds.....
(a) exponential splines
reference date : January 4th, 2016
number of iterations : 7291
(b) simple polynomial
reference date : January 4th, 2016
number of iterations : 268
(c) Nelson-Siegel
reference date : January 4th, 2016
number of iterations : 3013
(d) cubic B-splines
reference date : January 4th, 2016
number of iterations : 590
(e) Svensson
reference date : January 4th, 2016
number of iterations : 3220
Output Yield and basis point difference from Price for each curve. In this
case,
tenor | coupon | Yield | (btstrp)|(exp spl)|(s
poly)|(Nel-Sie)|(CubBSpl)|(Svensson)
2.000 | 1.000 | 0.010240 | 0.000 | 86.733 | 12.163 | 40.028 | -1.579 |
0.827
3.000 | 1.250 | 0.013246 | 0.000 | 55.112 | -3.508 | 14.530 | -2.265 |
-2.218
5.000 | 1.750 | 0.017528 | 0.000 | 18.551 | -9.105 | -10.589 | 6.730 |
3.471
7.000 | 2.125 | 0.020898 | 0.000 | -11.513 | -11.285 | -29.611 | -3.446 |
-2.930
9.917 | 2.250 | 0.022867 | -0.000 | -25.030 | 12.185 | -27.719 | 0.312 |
0.866
29.917 | 3.000 | 0.030319 | 0.000 | -49.796 | -0.337 | 18.809 | 0.000 |
-0.015
--
View this message in context: http://quantlib.10058.n7.nabble.com/FittedBondCurve-Example-using-Real-UST-OTR-Bonds-tp17234.html
Sent from the quantlib-users mailing list archive at Nabble.com.
------------------------------------------------------------------------------
_______________________________________________
QuantLib-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/quantlib-users
<http://leanpub.com/implementingquantlib>
<http://implementingquantlib.com>
<http://twitter.com/lballabio>
Free forum by Nabble | Disable Popup Ads | Edit this page |