Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
bonds.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
19#include "toplevelfixture.hpp"
20#include <boost/test/unit_test.hpp>
21#include <ql/cashflows/fixedratecoupon.hpp>
22#include <ql/quotes/simplequote.hpp>
23#include <ql/termstructures/credit/flathazardrate.hpp>
24#include <ql/termstructures/yield/flatforward.hpp>
25#include <ql/time/calendars/weekendsonly.hpp>
26#include <ql/time/schedule.hpp>
29
30#include <boost/make_shared.hpp>
31
32using namespace boost::unit_test_framework;
33using namespace QuantLib;
34
35BOOST_FIXTURE_TEST_SUITE(QuantExtTestSuite, qle::test::TopLevelFixture)
36
37BOOST_AUTO_TEST_SUITE(BondsTest)
38
39BOOST_AUTO_TEST_CASE(testBondSpreads) {
40
41 BOOST_TEST_MESSAGE("Testing QuantExt bond spread helper");
42
43 SavedSettings backup;
44 Settings::instance().evaluationDate() = Date(8, Dec, 2016);
45 Date today = Settings::instance().evaluationDate();
46
47 // market data
48 Handle<Quote> rateQuote(QuantLib::ext::make_shared<SimpleQuote>(0.02));
49 Handle<Quote> issuerSpreadQuote(QuantLib::ext::make_shared<SimpleQuote>(0.01));
50 DayCounter dc = Actual365Fixed();
51 Handle<YieldTermStructure> yts(QuantLib::ext::make_shared<FlatForward>(today, rateQuote, dc, Compounded, Semiannual));
52 Handle<DefaultProbabilityTermStructure> dpts(QuantLib::ext::make_shared<FlatHazardRate>(today, issuerSpreadQuote, dc));
53 Handle<Quote> bondSpecificSpread(QuantLib::ext::make_shared<SimpleQuote>(0.005));
54
55 // build the bond
56 Date startDate = today;
57 Date endDate = startDate + Period(10, Years);
58 Period tenor = 6 * Months;
59 Calendar calendar = WeekendsOnly();
60 BusinessDayConvention bdc = Following;
61 BusinessDayConvention bdcEnd = bdc;
62 DateGeneration::Rule rule = DateGeneration::Forward;
63 bool endOfMonth = false;
64 Date firstDate, lastDate;
65 Schedule schedule(startDate, endDate, tenor, calendar, bdc, bdcEnd, rule, endOfMonth, firstDate, lastDate);
66
67 Real redemption = 100.0;
68 Real couponRate = 0.04;
69 Leg leg =
70 FixedRateLeg(schedule).withNotionals(redemption).withCouponRates(couponRate, dc).withPaymentAdjustment(bdc);
71
72 QuantLib::ext::shared_ptr<QuantLib::Bond> bond(QuantLib::ext::make_shared<QuantLib::Bond>(0, WeekendsOnly(), today, leg));
73 Handle<Quote> recovery;
74 QuantLib::ext::shared_ptr<PricingEngine> pricingEngine(
75 QuantLib::ext::make_shared<QuantExt::DiscountingRiskyBondEngine>(yts, dpts, recovery, bondSpecificSpread, 1 * Months));
76 bond->setPricingEngine(pricingEngine);
77
78 Real price = bond->dirtyPrice();
79 BOOST_TEST_MESSAGE("Bond price = " << price);
80
81 // now calculated the implied bond spread, given the price
82 QuantLib::ext::shared_ptr<SimpleQuote> tmpSpread = QuantLib::ext::make_shared<SimpleQuote>(0.0);
83 Handle<Quote> tmpSpreadH(tmpSpread);
84 QuantLib::ext::shared_ptr<PricingEngine> tmpEngine;
85 tmpEngine.reset(new QuantExt::DiscountingRiskyBondEngine(yts, dpts, recovery, tmpSpreadH, 1 * Months));
86
87 Real impliedSpread = QuantExt::detail::ImpliedBondSpreadHelper::calculate(bond, tmpEngine, tmpSpread, price, false,
88 1.e-12, 10000, -0.02, 1.00);
89 BOOST_TEST_MESSAGE("Implied spread = " << impliedSpread);
90 BOOST_CHECK_CLOSE(impliedSpread, bondSpecificSpread->value(), 0.0001);
91
92 Real price2 = bond->dirtyPrice();
93 BOOST_CHECK_EQUAL(price, price2);
94
95 // which spread would mean the bond price is par?
96 Real parRedemption = 100.0;
98 bond, tmpEngine, tmpSpread, parRedemption, false, 1.e-12, 10000, -0.02, 1.00);
99 BOOST_TEST_MESSAGE("Par bond price would require spread of " << impliedSpreadPar);
100 BOOST_CHECK_EQUAL(
101 price, bond->dirtyPrice()); // ensure hypothetical impliedSpread calc has not affected the original position
102
103 QuantLib::ext::dynamic_pointer_cast<SimpleQuote>(*bondSpecificSpread)->setValue(impliedSpreadPar);
104 Real pricePar = bond->dirtyPrice();
105 BOOST_TEST_MESSAGE("Bond spread of " << bondSpecificSpread->value() << " means price of " << pricePar);
106 BOOST_CHECK_CLOSE(pricePar, parRedemption, 0.0001);
107
108 // now check that bond pricing works even if no credit curve exists
109
110 dpts = Handle<DefaultProbabilityTermStructure>();
111 pricingEngine.reset(new QuantExt::DiscountingRiskyBondEngine(yts, dpts, recovery, bondSpecificSpread, 1 * Months));
112 tmpEngine.reset(new QuantExt::DiscountingRiskyBondEngine(yts, dpts, recovery, tmpSpreadH, 1 * Months));
113 bond->setPricingEngine(pricingEngine);
114 Real priceNoIssuerCurve = bond->dirtyPrice();
115 BOOST_TEST_MESSAGE("Bond price (ignoring issuer spread) = " << priceNoIssuerCurve);
116 impliedSpread = QuantExt::detail::ImpliedBondSpreadHelper::calculate(bond, tmpEngine, tmpSpread, priceNoIssuerCurve,
117 false, 1.e-12, 10000, -0.02, 1.00);
118 BOOST_TEST_MESSAGE("Bond spread (ignoring issuer spread) = " << impliedSpread);
119 BOOST_CHECK_CLOSE(impliedSpread, bondSpecificSpread->value(), 0.0001);
120
121 // which spread would mean the bond price is par?
122 impliedSpreadPar = QuantExt::detail::ImpliedBondSpreadHelper::calculate(bond, tmpEngine, tmpSpread, parRedemption,
123 false, 1.e-12, 10000, -0.02, 1.00);
124 BOOST_TEST_MESSAGE("Par bond price would require spread of " << impliedSpreadPar);
125 BOOST_CHECK_CLOSE(impliedSpreadPar, bondSpecificSpread->value() + issuerSpreadQuote->value(), 0.0001);
126 QuantLib::ext::dynamic_pointer_cast<SimpleQuote>(*bondSpecificSpread)->setValue(impliedSpreadPar);
127 pricePar = bond->dirtyPrice();
128 BOOST_TEST_MESSAGE("Bond spread of " << bondSpecificSpread->value() << " means price of " << pricePar);
129 BOOST_CHECK_CLOSE(pricePar, parRedemption, 0.0001);
130}
131BOOST_AUTO_TEST_SUITE_END()
132
133BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(testBondSpreads)
Definition: bonds.cpp:39
static QuantLib::Real calculate(const QuantLib::ext::shared_ptr< QuantLib::Bond > &bond, const QuantLib::ext::shared_ptr< QuantLib::PricingEngine > &engine, const QuantLib::ext::shared_ptr< QuantLib::SimpleQuote > &spreadQuote, QuantLib::Real targetValue, bool isCleanPrice, QuantLib::Real accuracy, QuantLib::Natural maxEvaluations, QuantLib::Real minSpread, QuantLib::Real maxSpread)
utilities for implied bond credit spread calculation
Fixture that can be used at top level.