20#include <boost/make_shared.hpp>
21#include <boost/test/unit_test.hpp>
22#include <ql/currencies/all.hpp>
23#include <ql/indexes/ibor/gbplibor.hpp>
24#include <ql/indexes/ibor/usdlibor.hpp>
25#include <ql/quotes/simplequote.hpp>
26#include <ql/termstructures/yield/discountcurve.hpp>
27#include <ql/termstructures/yield/flatforward.hpp>
28#include <ql/termstructures/yield/piecewiseyieldcurve.hpp>
29#include <ql/time/calendars/all.hpp>
30#include <ql/time/daycounters/actual360.hpp>
31#include <ql/types.hpp>
36using namespace boost::unit_test_framework;
45 Natural settlementDays;
46 Calendar domesticCalendar, foreignCalendar, payCalendar;
47 BusinessDayConvention payConvention;
50 Currency foreignCurrency, domesticCurrency;
53 QuantLib::ext::shared_ptr<SimpleQuote> spotFxQuote;
54 QuantLib::ext::shared_ptr<SimpleQuote> spreadQuote;
55 Handle<YieldTermStructure> domesticProjCurve;
56 Handle<YieldTermStructure> domesticDiscCurve;
57 Handle<YieldTermStructure> foreignProjCurve;
58 QuantLib::ext::shared_ptr<IborIndex> domesticIndex;
59 QuantLib::ext::shared_ptr<IborIndex> foreignIndex;
60 QuantLib::ext::shared_ptr<CrossCcyBasisMtMResetSwapHelper>
helper;
63 asof = Date(11, Sep, 2018);
65 domesticCalendar = UnitedStates(UnitedStates::Settlement);
66 foreignCalendar = UnitedKingdom();
67 payCalendar = JointCalendar(domesticCalendar, foreignCalendar);
68 payConvention = Following;
71 domesticCurrency = USDCurrency();
72 foreignCurrency = GBPCurrency();
73 dayCount = Actual360();
74 foreignNominal = 10000000.0;
75 spotFxQuote = QuantLib::ext::make_shared<SimpleQuote>(1.2);
76 spreadQuote = QuantLib::ext::make_shared<SimpleQuote>(-0.0015);
80 Handle<YieldTermStructure>(QuantLib::ext::make_shared<FlatForward>(0, domesticCalendar, 0.02, Actual365Fixed()));
82 Handle<YieldTermStructure>(QuantLib::ext::make_shared<FlatForward>(0, foreignCalendar, 0.03, Actual365Fixed()));
84 Handle<YieldTermStructure>(QuantLib::ext::make_shared<FlatForward>(0, domesticCalendar, 0.01, Actual365Fixed()));
87 foreignIndex = QuantLib::ext::make_shared<GBPLibor>(3 * Months, foreignProjCurve);
88 domesticIndex = QuantLib::ext::make_shared<USDLibor>(3 * Months, domesticProjCurve);
92QuantLib::ext::shared_ptr<CrossCcyBasisMtMResetSwap> makeTestSwap(
const CommonVars& vars,
93 const Handle<YieldTermStructure>& foreignDiscCurve) {
95 Date referenceDate = Settings::instance().evaluationDate();
96 referenceDate = vars.payCalendar.adjust(referenceDate);
97 Date start = vars.payCalendar.advance(referenceDate, vars.settlementDays * Days);
98 Date end = start + vars.tenor;
99 Schedule schedule(start, end, 3 * Months, vars.payCalendar, vars.payConvention, vars.payConvention,
100 DateGeneration::Backward,
false);
102 QuantLib::ext::shared_ptr<FxIndex> fxIndex = QuantLib::ext::make_shared<FxIndex>(
103 "dummy", vars.settlementDays, vars.foreignCurrency, vars.domesticCurrency, vars.payCalendar,
104 Handle<Quote>(vars.spotFxQuote), foreignDiscCurve, vars.domesticDiscCurve);
106 vars.foreignNominal, vars.foreignCurrency, schedule, vars.foreignIndex, vars.spreadQuote->value(),
107 vars.domesticCurrency, schedule, vars.domesticIndex, 0.0, fxIndex,
false));
109 QuantLib::ext::shared_ptr<PricingEngine> engine =
110 QuantLib::ext::make_shared<CrossCcySwapEngine>(vars.domesticCurrency, vars.domesticDiscCurve, vars.foreignCurrency,
111 foreignDiscCurve, Handle<Quote>(vars.spotFxQuote));
112 swap->setPricingEngine(engine);
117Handle<YieldTermStructure> bootstrappedCurve(CommonVars& vars) {
120 vector<QuantLib::ext::shared_ptr<RateHelper> > helpers(1);
122 Handle<Quote>(vars.spreadQuote), Handle<Quote>(vars.spotFxQuote), vars.settlementDays, vars.payCalendar,
123 vars.tenor, vars.payConvention, vars.foreignIndex, vars.domesticIndex, Handle<YieldTermStructure>(),
124 vars.domesticDiscCurve));
125 helpers[0] = vars.helper;
128 return Handle<YieldTermStructure>(
129 QuantLib::ext::make_shared<PiecewiseYieldCurve<Discount, LogLinear> >(0, NullCalendar(), helpers, Actual365Fixed()));
135BOOST_AUTO_TEST_SUITE(CrossCcyBasisMtMResetSwapHelperTest)
139 BOOST_TEST_MESSAGE(
"Test simple bootstrap against cross currency MtM resetting swap");
141 SavedSettings backup;
143 Settings::instance().evaluationDate() = vars.asof;
146 Handle<YieldTermStructure> discCurve = bootstrappedCurve(vars);
149 QuantLib::ext::shared_ptr<CrossCcyBasisMtMResetSwap> swap = makeTestSwap(vars, discCurve);
153 BOOST_CHECK_SMALL(swap->NPV(), tol);
157 BOOST_CHECK_CLOSE(vars.spreadQuote->value(), swap->fairForeignSpread(), relTol);
160 DiscountFactor expDisc = 0.91155524911218166;
161 BOOST_CHECK_CLOSE(expDisc, discCurve->discount(vars.asof + 5 * Years), relTol);
166 BOOST_TEST_MESSAGE(
"Test rebootstrap under spot FX change");
168 SavedSettings backup;
172 Settings::instance().evaluationDate() = vars.asof;
175 Handle<YieldTermStructure> discCurve = bootstrappedCurve(vars);
178 QuantLib::ext::shared_ptr<CrossCcyBasisMtMResetSwap> swap = makeTestSwap(vars, discCurve);
182 BOOST_CHECK_SMALL(swap->NPV(), absTol);
186 BOOST_CHECK_CLOSE(vars.spreadQuote->value(), swap->fairForeignSpread(), relTol);
189 DiscountFactor expDisc = 0.91155524911218166;
190 BOOST_CHECK_CLOSE(expDisc, discCurve->discount(vars.asof + 5 * Years), relTol);
193 BOOST_CHECK_CLOSE(vars.spotFxQuote->value(), std::fabs(vars.helper->swap()->leg(2).front()->amount()), relTol);
196 vars.spotFxQuote->setValue(vars.spotFxQuote->value() * 1.1);
199 swap = makeTestSwap(vars, discCurve);
202 BOOST_CHECK_SMALL(swap->NPV(), absTol);
205 BOOST_CHECK_CLOSE(expDisc, discCurve->discount(vars.asof + 5 * Years), relTol);
208 BOOST_CHECK_CLOSE(vars.spotFxQuote->value(), std::fabs(vars.helper->swap()->leg(2).front()->amount()), relTol);
213 BOOST_TEST_MESSAGE(
"Test rebootstrap under helper spread change");
215 SavedSettings backup;
219 Settings::instance().evaluationDate() = vars.asof;
222 Handle<YieldTermStructure> discCurve = bootstrappedCurve(vars);
225 QuantLib::ext::shared_ptr<CrossCcyBasisMtMResetSwap> swap = makeTestSwap(vars, discCurve);
229 BOOST_CHECK_SMALL(swap->NPV(), absTol);
233 BOOST_CHECK_CLOSE(vars.spreadQuote->value(), swap->fairForeignSpread(), relTol);
236 DiscountFactor expDisc = 0.91155524911218166;
237 BOOST_CHECK_CLOSE(expDisc, discCurve->discount(vars.asof + 5 * Years), relTol);
240 vars.spreadQuote->setValue(0.0015);
243 swap = makeTestSwap(vars, discCurve);
246 BOOST_CHECK_SMALL(swap->NPV(), absTol);
249 expDisc = 0.89807807922008731;
250 BOOST_CHECK_CLOSE(expDisc, discCurve->discount(vars.asof + 5 * Years), relTol);
253 BOOST_CHECK_CLOSE(vars.spreadQuote->value(), swap->fairForeignSpread(), relTol);
258 BOOST_TEST_MESSAGE(
"Test rebootstrap after moving evaluation date");
260 SavedSettings backup;
264 Settings::instance().evaluationDate() = vars.asof;
267 Handle<YieldTermStructure> discCurve = bootstrappedCurve(vars);
270 QuantLib::ext::shared_ptr<CrossCcyBasisMtMResetSwap> swap = makeTestSwap(vars, discCurve);
274 BOOST_CHECK_SMALL(swap->NPV(), absTol);
278 BOOST_CHECK_CLOSE(vars.spreadQuote->value(), swap->fairForeignSpread(), relTol);
281 DiscountFactor expDisc = 0.91155524911218166;
282 BOOST_CHECK_CLOSE(expDisc, discCurve->discount(vars.asof + 5 * Years), relTol);
285 BOOST_CHECK_EQUAL(swap->startDate(), vars.helper->swap()->startDate());
288 vars.asof = vars.asof + 1 * Days;
289 Settings::instance().evaluationDate() = vars.asof;
292 swap = makeTestSwap(vars, discCurve);
295 BOOST_CHECK_SMALL(swap->NPV(), absTol);
298 expDisc = 0.91155524848230363;
299 BOOST_CHECK_CLOSE(expDisc, discCurve->discount(vars.asof + 5 * Years), relTol);
302 BOOST_CHECK_EQUAL(swap->startDate(), vars.helper->swap()->startDate());
305BOOST_AUTO_TEST_SUITE_END()
307BOOST_AUTO_TEST_SUITE_END()
Cross Ccy Basis MtM Reset Swap Rate Helper.
Cross currency basis MtM resettable swap.
Cross currency basis swap helper with MTM reset.
Cross currency swap engine.
QuantLib::BootstrapHelper< QuantLib::OptionletVolatilityStructure > helper
BOOST_AUTO_TEST_CASE(testBootstrap)
Fixture that can be used at top level.