Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
discountratiomodifiedcurve.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2018 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#include "toplevelfixture.hpp"
19#include <boost/assign/list_of.hpp>
20#include <boost/make_shared.hpp>
21#include <boost/test/unit_test.hpp>
22#include <ql/math/comparison.hpp>
23#include <ql/settings.hpp>
24#include <ql/termstructures/yield/discountcurve.hpp>
25#include <ql/termstructures/yield/flatforward.hpp>
26#include <ql/termstructures/yield/zerocurve.hpp>
27#include <ql/time/calendars/nullcalendar.hpp>
29
31using namespace QuantLib;
32using namespace boost::unit_test_framework;
33using namespace boost::assign;
34using std::vector;
35
36BOOST_FIXTURE_TEST_SUITE(QuantExtTestSuite, qle::test::TopLevelFixture)
37
38BOOST_AUTO_TEST_SUITE(DiscountingRatioModifiedCurveTest)
39
40BOOST_AUTO_TEST_CASE(testStandardCurves) {
41
42 BOOST_TEST_MESSAGE("Testing discount ratio modified curve with some standard curves");
43
44 SavedSettings backup;
45
46 Date today(15, Aug, 2018);
47 Settings::instance().evaluationDate() = today;
48
49 Actual365Fixed dc;
50
51 // Base curve with fixed reference date of 15th Aug 2018
52 vector<Date> baseDates = list_of(today)(today + 1 * Years);
53 vector<Real> baseDfs = list_of(1.0)(0.98);
54 Handle<YieldTermStructure> baseCurve(QuantLib::ext::make_shared<DiscountCurve>(baseDates, baseDfs, dc));
55 baseCurve->enableExtrapolation();
56
57 // Numerator curve with fixed reference date of 15th Aug 2018
58 vector<Date> numDates = list_of(today)(today + 1 * Years)(today + 2 * Years);
59 vector<Real> numZeroes = list_of(0.025)(0.025)(0.026);
60 Handle<YieldTermStructure> numCurve(QuantLib::ext::make_shared<ZeroCurve>(numDates, numZeroes, dc));
61 numCurve->enableExtrapolation();
62
63 // Denominator curve with floating reference date
64 Handle<YieldTermStructure> denCurve(QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.0255, dc));
65
66 DiscountRatioModifiedCurve curve(baseCurve, numCurve, denCurve);
67
68 Date discountDate = today + 18 * Months;
69 BOOST_CHECK(
70 close(curve.discount(discountDate),
71 baseCurve->discount(discountDate) * numCurve->discount(discountDate) / denCurve->discount(discountDate)));
72
73 discountDate = today + 3 * Years;
74 BOOST_CHECK(
75 close(curve.discount(discountDate),
76 baseCurve->discount(discountDate) * numCurve->discount(discountDate) / denCurve->discount(discountDate)));
77
78 // When we change evaluation date, we may not get what we expect here because reference date is taken from the
79 // base curve which has been set up here with a fixed reference date. However, the denominator curve has been
80 // set up here with a floating reference date. See the warning in the ctor of DiscountRatioModifiedCurve
81 Settings::instance().evaluationDate() = today + 3 * Months;
82 BOOST_TEST_MESSAGE("Changed evaluation date to " << Settings::instance().evaluationDate());
83
84 BOOST_CHECK(
85 !close(curve.discount(discountDate), baseCurve->discount(discountDate) * numCurve->discount(discountDate) /
86 denCurve->discount(discountDate)));
87 Time t = dc.yearFraction(curve.referenceDate(), discountDate);
88 BOOST_CHECK(close(curve.discount(discountDate),
89 baseCurve->discount(discountDate) * numCurve->discount(discountDate) / denCurve->discount(t)));
90}
91
92BOOST_AUTO_TEST_CASE(testExtrapolationSettings) {
93
94 BOOST_TEST_MESSAGE("Testing extrapolation settings for discount ratio modified curve");
95
96 SavedSettings backup;
97
98 Date today(15, Aug, 2018);
99 Settings::instance().evaluationDate() = today;
100
101 Actual365Fixed dc;
102
103 // Base curve with fixed reference date of 15th Aug 2018
104 vector<Date> baseDates = list_of(today)(Date(15, Aug, 2019));
105 vector<Real> baseDfs = list_of(1.0)(0.98);
106 Handle<YieldTermStructure> baseCurve(QuantLib::ext::make_shared<DiscountCurve>(baseDates, baseDfs, dc));
107
108 // Numerator curve with fixed reference date of 15th Aug 2018
109 vector<Date> numDates = list_of(today)(Date(15, Aug, 2019))(Date(15, Aug, 2020));
110 vector<Real> numZeroes = list_of(0.025)(0.025)(0.026);
111 Handle<YieldTermStructure> numCurve(QuantLib::ext::make_shared<ZeroCurve>(numDates, numZeroes, dc));
112
113 // Denominator curve with floating reference date
114 Handle<YieldTermStructure> denCurve(QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.0255, dc));
115
116 // Create the discount ratio curve
117 DiscountRatioModifiedCurve curve(baseCurve, numCurve, denCurve);
118
119 // Extrapolation is always true
120 BOOST_CHECK(curve.allowsExtrapolation());
121
122 // Max date is maximum possible date
123 BOOST_CHECK_EQUAL(curve.maxDate(), Date::maxDate());
124
125 // Extrapolation is determined by underlying curves
126 BOOST_CHECK_NO_THROW(curve.discount(Date(15, Aug, 2019)));
127 BOOST_CHECK_THROW(curve.discount(Date(15, Aug, 2019) + 1 * Days), QuantLib::Error);
128 baseCurve->enableExtrapolation();
129 BOOST_CHECK_NO_THROW(curve.discount(Date(15, Aug, 2019) + 1 * Days));
130 BOOST_CHECK_THROW(curve.discount(Date(15, Aug, 2020) + 1 * Days), QuantLib::Error);
131 numCurve->enableExtrapolation();
132 BOOST_CHECK_NO_THROW(curve.discount(Date(15, Aug, 2020) + 1 * Days));
133}
134
135BOOST_AUTO_TEST_CASE(testConstructionNullUnderlyingCurvesThrow) {
136
137 BOOST_TEST_MESSAGE("Testing construction with null underlying curves throw");
138
139 QuantLib::ext::shared_ptr<DiscountRatioModifiedCurve> curve;
140
141 // All empty handles throw
142 Handle<YieldTermStructure> baseCurve;
143 Handle<YieldTermStructure> numCurve;
144 Handle<YieldTermStructure> denCurve;
145 BOOST_CHECK_THROW(curve = QuantLib::ext::make_shared<DiscountRatioModifiedCurve>(baseCurve, numCurve, denCurve),
146 QuantLib::Error);
147
148 // Numerator and denominator empty handles throw
149 Handle<YieldTermStructure> baseCurve_1(
150 QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.0255, Actual365Fixed()));
151 BOOST_CHECK_THROW(curve = QuantLib::ext::make_shared<DiscountRatioModifiedCurve>(baseCurve_1, numCurve, denCurve),
152 QuantLib::Error);
153
154 // Denominator empty handles throw
155 Handle<YieldTermStructure> numCurve_1(QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.0255, Actual365Fixed()));
156 BOOST_CHECK_THROW(curve = QuantLib::ext::make_shared<DiscountRatioModifiedCurve>(baseCurve_1, numCurve_1, denCurve),
157 QuantLib::Error);
158
159 // No empty handles succeeds
160 Handle<YieldTermStructure> denCurve_1(QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.0255, Actual365Fixed()));
161 BOOST_CHECK_NO_THROW(curve = QuantLib::ext::make_shared<DiscountRatioModifiedCurve>(baseCurve_1, numCurve_1, denCurve_1));
162}
163
164BOOST_AUTO_TEST_CASE(testLinkingNullUnderlyingCurvesThrow) {
165
166 BOOST_TEST_MESSAGE("Testing that linking with null underlying curves throw");
167
168 QuantLib::ext::shared_ptr<DiscountRatioModifiedCurve> curve;
169
170 // All empty handles throw
171 RelinkableHandle<YieldTermStructure> baseCurve(
172 QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.0255, Actual365Fixed()));
173 RelinkableHandle<YieldTermStructure> numCurve(
174 QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.0255, Actual365Fixed()));
175 RelinkableHandle<YieldTermStructure> denCurve(
176 QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.0255, Actual365Fixed()));
177
178 // Curve building succeeds since no empty handles
179 BOOST_CHECK_NO_THROW(curve = QuantLib::ext::make_shared<DiscountRatioModifiedCurve>(baseCurve, numCurve, denCurve));
180
181 // Switching base curve to empty handle should give a failure
182 BOOST_CHECK_THROW(baseCurve.linkTo(QuantLib::ext::shared_ptr<YieldTermStructure>()), QuantLib::Error);
183 BOOST_CHECK_NO_THROW(baseCurve.linkTo(*numCurve));
184
185 // Switching numerator curve to empty handle should give a failure
186 BOOST_CHECK_THROW(numCurve.linkTo(QuantLib::ext::shared_ptr<YieldTermStructure>()), QuantLib::Error);
187 BOOST_CHECK_NO_THROW(numCurve.linkTo(*denCurve));
188
189 // Switching denominator curve to empty handle should give a failure
190 BOOST_CHECK_THROW(denCurve.linkTo(QuantLib::ext::shared_ptr<YieldTermStructure>()), QuantLib::Error);
191}
192
193BOOST_AUTO_TEST_SUITE_END()
194
195BOOST_AUTO_TEST_SUITE_END()
const QuantLib::Date & referenceDate() const override
Returns the reference date from the base curve.
QuantLib::Date maxDate() const override
All range checks happen in the underlying curves.
discount curve modified by the ratio of two other discount curves
BOOST_AUTO_TEST_CASE(testStandardCurves)
Fixture that can be used at top level.