21#include <oret/toplevelfixture.hpp>
26#include <ql/cashflows/couponpricer.hpp>
27#include <ql/cashflows/iborcoupon.hpp>
28#include <ql/cashflows/simplecashflow.hpp>
29#include <ql/currencies/america.hpp>
30#include <ql/currencies/europe.hpp>
31#include <ql/indexes/iborindex.hpp>
32#include <ql/quotes/simplequote.hpp>
33#include <ql/termstructures/yield/flatforward.hpp>
34#include <ql/time/calendars/target.hpp>
35#include <ql/time/calendars/unitedstates.hpp>
36#include <ql/time/daycounters/actual360.hpp>
37#include <ql/time/daycounters/actual365fixed.hpp>
39#include <boost/test/unit_test.hpp>
43using namespace boost::unit_test_framework;
45struct RepresentativeFxOptionFixture :
public ore::test::TopLevelFixture {
47 RepresentativeFxOptionFixture() { Settings::instance().evaluationDate() = today; }
48 Date today = Date(20, Apr, 2021);
49 Handle<Quote> eurUsdSpot = Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(1.2));
51 Handle<YieldTermStructure> eurCurve = Handle<YieldTermStructure>(QuantLib::ext::make_shared<FlatForward>(today, 0.01, dc));
52 Handle<YieldTermStructure> usdCurve = Handle<YieldTermStructure>(QuantLib::ext::make_shared<FlatForward>(today, 0.03, dc));
55BOOST_AUTO_TEST_SUITE(OREDataTestSuite)
57BOOST_FIXTURE_TEST_SUITE(RepresentativeFxOptionTest, RepresentativeFxOptionFixture)
61 BOOST_TEST_MESSAGE(
"test reproducing simple cashflows");
63 Real tol = 1E-12, tol2 = 1E-10;
65 Date refDate = today + 5 * Years;
67 Real eurAmount = 35000.0;
68 Real usdAmount = 14222.0;
69 Leg eurLeg = {QuantLib::ext::make_shared<SimpleCashFlow>(eurAmount, refDate)};
70 Leg usdLeg = {QuantLib::ext::make_shared<SimpleCashFlow>(usdAmount, refDate)};
73 eurCurve, usdCurve, eurUsdSpot,
true);
75 BOOST_CHECK_EQUAL(matcher1.currency1(),
"EUR");
76 BOOST_CHECK_EQUAL(matcher1.currency2(),
"USD");
77 BOOST_CHECK_CLOSE(matcher1.amount1(), -eurAmount, tol);
78 BOOST_CHECK_CLOSE(matcher1.amount2(), usdAmount, tol);
81 eurCurve, usdCurve, eurUsdSpot,
true);
83 BOOST_CHECK_EQUAL(matcher2.currency1(),
"EUR");
84 BOOST_CHECK_EQUAL(matcher2.currency2(),
"USD");
85 BOOST_CHECK_CLOSE(matcher2.amount1(), eurAmount, tol);
86 BOOST_CHECK_CLOSE(matcher2.amount2(), -usdAmount, tol);
89 eurCurve, usdCurve, eurUsdSpot,
true);
91 BOOST_CHECK_EQUAL(matcher3.currency1(),
"EUR");
92 BOOST_CHECK_EQUAL(matcher3.currency2(),
"USD");
93 BOOST_CHECK_CLOSE(matcher3.amount1(), eurAmount, tol);
94 BOOST_CHECK_CLOSE(matcher3.amount2(), usdAmount, tol);
97 eurCurve, usdCurve, eurUsdSpot,
true);
99 BOOST_CHECK_EQUAL(matcher4.currency1(),
"EUR");
100 BOOST_CHECK_EQUAL(matcher4.currency2(),
"USD");
101 BOOST_CHECK_CLOSE(matcher4.amount1(), -eurAmount, tol);
102 BOOST_CHECK_CLOSE(matcher4.amount2(), -usdAmount, tol);
107 BOOST_CHECK_EQUAL(matcher5.currency1(),
"EUR");
108 BOOST_CHECK_EQUAL(matcher5.currency2(),
"USD");
109 BOOST_CHECK_CLOSE(matcher5.amount1(), -eurAmount, tol);
110 BOOST_CHECK_SMALL(matcher5.amount2(), tol2);
114 BOOST_CHECK_EQUAL(matcher6.currency1(),
"EUR");
115 BOOST_CHECK_EQUAL(matcher6.currency2(),
"USD");
116 BOOST_CHECK_SMALL(matcher6.amount1(), tol2);
117 BOOST_CHECK_SMALL(matcher6.amount2(), tol2);
122 BOOST_TEST_MESSAGE(
"test fx linked cashflow");
126 Date refDate = today + 5 * Years;
127 Date fixDate = UnitedStates(UnitedStates::Settlement).advance(refDate, -2 * Days);
129 auto fxSpotScen = QuantLib::ext::make_shared<SimpleQuote>(eurUsdSpot->value());
130 auto fxIndex = QuantLib::ext::make_shared<FxIndex>(
"dummy", 2, EURCurrency(), USDCurrency(), UnitedStates(UnitedStates::Settlement),
131 Handle<Quote>(fxSpotScen), eurCurve, usdCurve);
132 Real forAmount = 100000.0;
134 Leg leg = {QuantLib::ext::make_shared<FXLinkedCashFlow>(refDate, fixDate, forAmount, fxIndex)};
138 BOOST_CHECK_EQUAL(matcher.currency1(),
"EUR");
139 BOOST_CHECK_EQUAL(matcher.currency2(),
"USD");
141 Real eurAmount = matcher.amount1();
142 Real usdAmount = matcher.amount2();
146 BOOST_CHECK_CLOSE(eurAmount * eurUsdSpot->value() + usdAmount, leg.front()->amount() * usdCurve->discount(refDate),
151 fxSpotScen->setValue(eurUsdSpot->value() * 1.01);
152 Real upNpv = leg.front()->amount() * usdCurve->discount(refDate);
154 fxSpotScen->setValue(eurUsdSpot->value() * 0.99);
155 Real downNpv = leg.front()->amount() * usdCurve->discount(refDate);
157 BOOST_CHECK_CLOSE(eurAmount, (upNpv - downNpv) / (eurUsdSpot->value() * 0.02), tol);
162 BOOST_TEST_MESSAGE(
"test fx linked floating rate coupon");
166 Date refDate = today + 5 * Years;
167 Date fixDate = UnitedStates(UnitedStates::Settlement).advance(refDate, -2 * Days);
169 auto fxSpotScen = QuantLib::ext::make_shared<SimpleQuote>(eurUsdSpot->value());
170 auto fxIndex = QuantLib::ext::make_shared<FxIndex>(
"dummy", 2, EURCurrency(), USDCurrency(), UnitedStates(UnitedStates::Settlement),
171 Handle<Quote>(fxSpotScen), eurCurve, usdCurve);
172 Real forAmount = 100000.0;
174 auto iborIndex = QuantLib::ext::make_shared<IborIndex>(
"dummyIbor", 6 * Months, 2, EURCurrency(), TARGET(), Following,
175 false, Actual360(), eurCurve);
176 Date start(refDate - 6 * Months), end(refDate);
177 auto iborCoupon = QuantLib::ext::make_shared<IborCoupon>(refDate, 1.0, start, end, 2, iborIndex, 1.0, 0.0);
178 iborCoupon->setPricer(QuantLib::ext::make_shared<BlackIborCouponPricer>());
180 Leg leg = {QuantLib::ext::make_shared<FloatingRateFXLinkedNotionalCoupon>(fixDate, forAmount, fxIndex, iborCoupon)};
184 BOOST_CHECK_EQUAL(matcher.currency1(),
"EUR");
185 BOOST_CHECK_EQUAL(matcher.currency2(),
"USD");
187 Real eurAmount = matcher.amount1();
188 Real usdAmount = matcher.amount2();
192 BOOST_CHECK_CLOSE(eurAmount * eurUsdSpot->value() + usdAmount, leg.front()->amount() * usdCurve->discount(refDate),
197 fxSpotScen->setValue(eurUsdSpot->value() * 1.01);
198 Real upNpv = leg.front()->amount() * usdCurve->discount(refDate);
200 fxSpotScen->setValue(eurUsdSpot->value() * 0.99);
201 Real downNpv = leg.front()->amount() * usdCurve->discount(refDate);
203 BOOST_CHECK_CLOSE(eurAmount, (upNpv - downNpv) / (eurUsdSpot->value() * 0.02), tol);
206BOOST_AUTO_TEST_SUITE_END()
208BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(testSimpleCashflows)