Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
multilegoption.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2017 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 <boost/test/unit_test.hpp>
21//#include <oret/toplevelfixture.hpp>
22
24
29
30#include <ql/cashflows/simplecashflow.hpp>
31#include <ql/currencies/america.hpp>
32#include <ql/currencies/europe.hpp>
33#include <ql/indexes/ibor/euribor.hpp>
34#include <ql/instruments/swaption.hpp>
35#include <ql/pricingengines/swap/discountingswapengine.hpp>
36#include <ql/quotes/simplequote.hpp>
37#include <ql/termstructures/yield/flatforward.hpp>
38#include <ql/time/calendars/target.hpp>
39#include <ql/time/daycounters/actual360.hpp>
40#include <ql/time/daycounters/thirty360.hpp>
41
42#include <boost/timer/timer.hpp>
43
44using namespace QuantLib;
45using namespace QuantExt;
46using namespace boost::unit_test_framework;
47
48namespace {
49struct BermudanTestData : public qle::test::TopLevelFixture {
50 BermudanTestData()
51 : evalDate(12, January, 2015), yts(QuantLib::ext::make_shared<FlatForward>(evalDate, 0.02, Actual365Fixed())),
52 euribor6m(QuantLib::ext::make_shared<Euribor>(6 * Months, yts)), effectiveDate(TARGET().advance(evalDate, 2 * Days)),
53 startDate(TARGET().advance(effectiveDate, 1 * Years)), maturityDate(TARGET().advance(startDate, 9 * Years)),
54 fixedSchedule(startDate, maturityDate, 1 * Years, TARGET(), ModifiedFollowing, ModifiedFollowing,
55 DateGeneration::Forward, false),
56 floatingSchedule(startDate, maturityDate, 6 * Months, TARGET(), ModifiedFollowing, ModifiedFollowing,
57 DateGeneration::Forward, false),
58 underlying(
59 QuantLib::ext::make_shared<VanillaSwap>(VanillaSwap(VanillaSwap::Payer, 1.0, fixedSchedule, 0.02, Thirty360(Thirty360::BondBasis),
60 floatingSchedule, euribor6m, 0.0, Actual360()))),
61 reversion(0.03) {
62 Settings::instance().evaluationDate() = evalDate;
63 for (Size i = 0; i < 9; ++i) {
64 exerciseDates.push_back(TARGET().advance(fixedSchedule[i], -2 * Days));
65 }
66 exercise = QuantLib::ext::make_shared<BermudanExercise>(exerciseDates, false);
67
68 swaption = QuantLib::ext::make_shared<Swaption>(underlying, exercise);
69 stepDates = std::vector<Date>(exerciseDates.begin(), exerciseDates.end() - 1);
70 sigmas = std::vector<Real>(stepDates.size() + 1);
71 for (Size i = 0; i < sigmas.size(); ++i) {
72 sigmas[i] = 0.0050 + (0.0080 - 0.0050) * std::exp(-0.2 * static_cast<double>(i));
73 }
74 stepTimes_a = Array(stepDates.size());
75 for (Size i = 0; i < stepDates.size(); ++i) {
76 stepTimes_a[i] = yts->timeFromReference(stepDates[i]);
77 }
78 sigmas_a = Array(sigmas.begin(), sigmas.end());
79 kappas_a = Array(sigmas_a.size(), reversion);
80 }
81 Date evalDate;
82 Handle<YieldTermStructure> yts;
83 QuantLib::ext::shared_ptr<IborIndex> euribor6m;
84 Date effectiveDate, startDate, maturityDate;
85 Schedule fixedSchedule, floatingSchedule;
86 QuantLib::ext::shared_ptr<VanillaSwap> underlying;
87 std::vector<Date> exerciseDates, stepDates;
88 std::vector<Real> sigmas;
89 QuantLib::ext::shared_ptr<Exercise> exercise;
90 QuantLib::ext::shared_ptr<Swaption> swaption;
91 Array stepTimes_a, sigmas_a, kappas_a;
92 Real reversion;
93}; // BermudanTestData
94} // namespace
95
96BOOST_FIXTURE_TEST_SUITE(OreAmcTestSuite, qle::test::TopLevelFixture)
97
98BOOST_AUTO_TEST_SUITE(AmcMultiLegOptionTest)
99
100BOOST_FIXTURE_TEST_CASE(testBermudanSwaption, BermudanTestData) {
101
102 BOOST_TEST_MESSAGE("Testing pricing of bermudan swaption as multi leg option vs numeric swaption engine");
103
104 auto multiLegOption = QuantLib::ext::make_shared<MultiLegOption>(
105 std::vector<Leg>{underlying->leg(0), underlying->leg(1)}, std::vector<bool>{true, false},
106 std::vector<Currency>{EURCurrency(), EURCurrency()}, exercise);
107
108 auto lgm_p = QuantLib::ext::make_shared<IrLgm1fPiecewiseConstantHullWhiteAdaptor>(EURCurrency(), yts, stepTimes_a, sigmas_a,
109 stepTimes_a, kappas_a);
110
111 auto xasset = Handle<CrossAssetModel>(
112 QuantLib::ext::make_shared<CrossAssetModel>(std::vector<QuantLib::ext::shared_ptr<Parametrization>>{lgm_p}));
113 auto lgm = QuantLib::ext::make_shared<LinearGaussMarkovModel>(lgm_p);
114
115 auto swaptionEngineLgm = QuantLib::ext::make_shared<NumericLgmSwaptionEngine>(lgm, 7.0, 16, 7.0, 32);
116 auto swapEngine = QuantLib::ext::make_shared<DiscountingSwapEngine>(yts);
117
118 auto mcMultiLegOptionEngine = QuantLib::ext::make_shared<McMultiLegOptionEngine>(
119 xasset, SobolBrownianBridge, SobolBrownianBridge, 25000, 0, 42, 42, 4, LsmBasisSystem::Monomial);
120
121 underlying->setPricingEngine(swapEngine);
122 swaption->setPricingEngine(swaptionEngineLgm);
123 Real npvUnd0 = underlying->NPV();
124 Real npv0 = swaption->NPV();
125 BOOST_TEST_MESSAGE("npv (numeric lgm swaption engine): underlying = " << npvUnd0 << ", option = " << npv0);
126
127 boost::timer::cpu_timer timer;
128 multiLegOption->setPricingEngine(mcMultiLegOptionEngine);
129 Real npvUnd1 = multiLegOption->result<Real>("underlyingNpv");
130 Real npv1 = multiLegOption->NPV();
131 timer.stop();
132 BOOST_TEST_MESSAGE("npv (multi leg option engine) : underlying = "
133 << npvUnd1 << ", option = " << npv1 << ", timing " << timer.elapsed().wall * 1e-6 << " ms");
134
135 BOOST_CHECK_SMALL(std::abs(npvUnd0 - npvUnd1), 1.0E-4);
136 BOOST_CHECK_SMALL(std::abs(npv0 - npv1), 1.0E-4);
137
138} // testBermudanSwaption
139
140BOOST_AUTO_TEST_CASE(testFxOption) {
141
142 BOOST_TEST_MESSAGE("Testing pricing of fx option as multi leg option vs analytic engine");
143
144 SavedSettings backup;
145 Date refDate(12, January, 2015);
146 Settings::instance().evaluationDate() = refDate;
147
148 auto yts_eur = Handle<YieldTermStructure>(QuantLib::ext::make_shared<FlatForward>(refDate, 0.02, Actual365Fixed()));
149 auto yts_usd = Handle<YieldTermStructure>(QuantLib::ext::make_shared<FlatForward>(refDate, 0.03, Actual365Fixed()));
150
151 auto lgm_eur_p = QuantLib::ext::make_shared<IrLgm1fConstantParametrization>(EURCurrency(), yts_eur, 0.01, 0.01);
152 auto lgm_usd_p = QuantLib::ext::make_shared<IrLgm1fConstantParametrization>(USDCurrency(), yts_usd, 0.01, 0.01);
153
154 Handle<Quote> fxspot(QuantLib::ext::make_shared<SimpleQuote>(0.9));
155
156 auto fx_p = QuantLib::ext::make_shared<FxBsConstantParametrization>(USDCurrency(), fxspot, 0.15);
157
158 Matrix corr(3, 3);
159 // clang-format off
160 corr[0][0] = 1.0; corr[0][1] = 0.2; corr[0][2] = 0.5;
161 corr[1][0] = 0.2; corr[1][1] = 1.0; corr[1][2] = 0.4;
162 corr[2][0] = 0.5; corr[2][1] = 0.4; corr[2][2] = 1.0;
163 // clang-format on
164
165 auto xasset = Handle<CrossAssetModel>(QuantLib::ext::make_shared<CrossAssetModel>(
166 std::vector<QuantLib::ext::shared_ptr<Parametrization>>{lgm_eur_p, lgm_usd_p, fx_p}, corr));
167
168 Date exDate(12, January, 2020);
169 auto exercise = QuantLib::ext::make_shared<EuropeanExercise>(exDate);
170 auto fxOption =
171 QuantLib::ext::make_shared<VanillaOption>(QuantLib::ext::make_shared<PlainVanillaPayoff>(Option::Call, 0.8), exercise);
172
173 Leg usdFlow, eurFlow;
174 usdFlow.push_back(QuantLib::ext::make_shared<SimpleCashFlow>(1.0, exDate + 1));
175 eurFlow.push_back(QuantLib::ext::make_shared<SimpleCashFlow>(-0.8, exDate + 1));
176
177 auto multiLegOption =
178 QuantLib::ext::make_shared<MultiLegOption>(std::vector<Leg>{eurFlow, usdFlow}, std::vector<bool>{false, false},
179 std::vector<Currency>{EURCurrency(), USDCurrency()}, exercise);
180
181 auto analyticFxOptionEngine = QuantLib::ext::make_shared<AnalyticCcLgmFxOptionEngine>(*xasset, 0);
182 fxOption->setPricingEngine(analyticFxOptionEngine);
183 Real npv0 = fxOption->NPV();
184 BOOST_TEST_MESSAGE("npv (analytic cclgm fx option engine): " << npv0);
185
186 // for european options there is no traning phase actually
187 auto mcMultiLegOptionEngine = QuantLib::ext::make_shared<McMultiLegOptionEngine>(
188 xasset, SobolBrownianBridge, SobolBrownianBridge, 25000, 0, 42, 42, 4, LsmBasisSystem::Monomial);
189
190 multiLegOption->setPricingEngine(mcMultiLegOptionEngine);
191 boost::timer::cpu_timer timer;
192 Real npv1 = multiLegOption->NPV();
193 timer.stop();
194 BOOST_TEST_MESSAGE("npv (multi leg option engine) : " << npv1 << ", timing " << timer.elapsed().wall * 1e-6
195 << " ms");
196
197 BOOST_CHECK_SMALL(std::abs(npv1 - npv0), 1.0E-4);
198
199} // testFxOption
200
201BOOST_AUTO_TEST_SUITE_END()
202
203BOOST_AUTO_TEST_SUITE_END()
analytic cc lgm fx option engine
cross asset model
Constant FX model parametrization.
MC engine for multi leg option instrument.
BOOST_AUTO_TEST_CASE(testFxOption)
BOOST_FIXTURE_TEST_CASE(testBermudanSwaption, BermudanTestData)
Fixture that can be used at top level.