20#include <boost/test/unit_test.hpp>
21#include <boost/test/data/test_case.hpp>
30#include <ql/time/date.hpp>
31#include <ql/cashflows/cmscoupon.hpp>
32#include <ql/cashflows/lineartsrpricer.hpp>
33#include <ql/termstructures/yieldtermstructure.hpp>
34#include <ql/termstructures/yield/flatforward.hpp>
35#include <ql/termstructures/volatility/swaption/swaptionconstantvol.hpp>
36#include <ql/indexes/swap/euriborswap.hpp>
43BOOST_AUTO_TEST_SUITE(DurationAdjustedCouponTest)
47 BOOST_TEST_MESSAGE(
"Testing duration adjusted cms coupons vs. vanilla cms coupon...");
49 Date today(25, January, 2021);
50 Settings::instance().evaluationDate() = today;
52 Handle<YieldTermStructure> discountCurve(
53 QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.01, Actual365Fixed()));
54 Handle<YieldTermStructure> forwardCurve(QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.02, Actual365Fixed()));
55 Handle<SwaptionVolatilityStructure> swaptionVol(QuantLib::ext::make_shared<ConstantSwaptionVolatility>(
56 0, NullCalendar(), Unadjusted, 0.0050, Actual365Fixed(), Normal));
57 Handle<Quote> reversion(QuantLib::ext::make_shared<SimpleQuote>(0.01));
59 Date startDate = Date(25, January, 2025);
60 Date endDate = Date(25, January, 2026);
61 Date payDate = Date(27, January, 2026);
63 auto index = QuantLib::ext::make_shared<EuriborSwapIsdaFixA>(10 * Years, forwardCurve, discountCurve);
65 CmsCoupon cmsCoupon(payDate, 1.0, startDate, endDate, fixingDays, index);
68 auto cmsPricer = QuantLib::ext::make_shared<LinearTsrPricer>(swaptionVol, reversion, discountCurve,
69 LinearTsrPricer::Settings().withRateBound(-2.0, 2.0));
71 auto durationAdjustedCmsPricer = QuantLib::ext::make_shared<DurationAdjustedCmsCouponTsrPricer>(
72 swaptionVol, QuantLib::ext::make_shared<LinearAnnuityMappingBuilder>(reversion), -2.0, 2.0);
74 cmsCoupon.setPricer(cmsPricer);
75 durationAdjustedCmsCoupon.setPricer(durationAdjustedCmsPricer);
77 BOOST_TEST_MESSAGE(
"cms coupon rate = " << cmsCoupon.rate());
78 BOOST_TEST_MESSAGE(
"cms coupon convexity adj = " << cmsCoupon.convexityAdjustment());
79 BOOST_TEST_MESSAGE(
"duration adjusted cms coupon rate = " << durationAdjustedCmsCoupon.rate());
80 BOOST_TEST_MESSAGE(
"dur adj cms coupon convexity adj = " << durationAdjustedCmsCoupon.convexityAdjustment());
84 BOOST_CHECK_CLOSE(cmsCoupon.rate(), durationAdjustedCmsCoupon.rate(), tol);
85 BOOST_CHECK_CLOSE(cmsCoupon.convexityAdjustment(), durationAdjustedCmsCoupon.convexityAdjustment(), tol);
90 BOOST_TEST_MESSAGE(
"Testing duration adjusted cms coupon historical rates...");
92 Date today(25, January, 2021);
93 Settings::instance().evaluationDate() = today;
95 Date startDate = Date(25, June, 2020);
96 Date endDate = Date(25, June, 2021);
97 Date payDate = Date(27, June, 2021);
100 Handle<YieldTermStructure> discountCurve(
101 QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.01, Actual365Fixed()));
102 Handle<YieldTermStructure> forwardCurve(QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.02, Actual365Fixed()));
104 auto index = QuantLib::ext::make_shared<EuriborSwapIsdaFixA>(10 * Years, forwardCurve, discountCurve);
106 Date fixingDate = index->fixingCalendar().advance(startDate, -(fixingDays * Days), Preceding);
107 Real fixingValue = 0.01;
108 index->addFixing(fixingDate, fixingValue);
112 QuantLib::ext::make_shared<DurationAdjustedCmsCouponTsrPricer>(Handle<SwaptionVolatilityStructure>(),
nullptr);
118 cpn0.setPricer(pricer);
119 cpn1.setPricer(pricer);
120 cpn10.setPricer(pricer);
122 BOOST_TEST_MESSAGE(
"duration = 0 : rate = " << cpn0.rate());
123 BOOST_TEST_MESSAGE(
"duration = 1 : rate = " << cpn1.rate());
124 BOOST_TEST_MESSAGE(
"duration = 10 : rate = " << cpn10.rate());
126 BOOST_TEST_MESSAGE(
"duration = 0 : indexFixing = " << cpn0.
indexFixing());
127 BOOST_TEST_MESSAGE(
"duration = 1 : indexFixing = " << cpn1.
indexFixing());
128 BOOST_TEST_MESSAGE(
"duration = 10 : indexFixing = " << cpn10.
indexFixing());
130 auto durationAdjustment = [](
const Real S,
const Size i) {
134 for (Size j = 0; j < i; ++j)
135 tmp += 1.0 / std::pow(1.0 + S, j + 1);
141 BOOST_CHECK_CLOSE(cpn0.rate(), fixingValue * durationAdjustment(fixingValue, 0), tol);
142 BOOST_CHECK_CLOSE(cpn1.rate(), fixingValue * durationAdjustment(fixingValue, 1), tol);
143 BOOST_CHECK_CLOSE(cpn10.rate(), fixingValue * durationAdjustment(fixingValue, 10), tol);
145 BOOST_CHECK_CLOSE(cpn0.
indexFixing(), fixingValue * durationAdjustment(fixingValue, 0), tol);
146 BOOST_CHECK_CLOSE(cpn1.
indexFixing(), fixingValue * durationAdjustment(fixingValue, 1), tol);
147 BOOST_CHECK_CLOSE(cpn10.
indexFixing(), fixingValue * durationAdjustment(fixingValue, 10), tol);
150BOOST_AUTO_TEST_SUITE_END()
152BOOST_AUTO_TEST_SUITE_END()
Rate indexFixing() const override
cms coupon scaled by a duration number
tsr coupon pricer for duration adjusted cms coupon
linear annuity mapping function f(S) = a*S+b
BOOST_AUTO_TEST_CASE(testAgainstCmsCoupon)
Fixture that can be used at top level.