Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
strippedoptionletadapter.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2019 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/assign.hpp>
20#include <boost/test/unit_test.hpp>
21#include <ql/quotes/simplequote.hpp>
22#include <ql/termstructures/volatility/optionlet/strippedoptionlet.hpp>
23#include <ql/time/calendars/unitedstates.hpp>
27
28using namespace QuantExt;
29using namespace QuantLib;
30using namespace boost::unit_test_framework;
31
32using boost::assign::list_of;
34using std::vector;
35
36namespace {
37
38// Fixture to create an optionlet surface that is used in the tests
39class F : public TopLevelFixture {
40public:
41 Date asof;
42 vector<Date> expiries;
43 vector<Rate> strikes;
44 DayCounter dc;
45 vector<vector<Handle<Quote> > > vols;
46 QuantLib::ext::shared_ptr<StrippedOptionlet> optionletSurface;
47
48 F() : expiries(2), strikes(2), dc(Actual365Fixed()), vols(2) {
49
50 // Set the evaluation date
51 asof = Date(17, Apr, 2019);
52 Settings::instance().evaluationDate() = asof;
53
54 // Inputs for the optionlet surface
55 Natural settlementDays = 2;
56 UnitedStates calendar(UnitedStates::Settlement);
57 BusinessDayConvention bdc = Following;
58 QuantLib::ext::shared_ptr<IborIndex> dummyIborIndex;
59 VolatilityType type = Normal;
60
61 expiries[0] = Date(17, Apr, 2020);
62 expiries[1] = Date(19, Apr, 2021);
63
64 strikes[0] = 0.02;
65 strikes[1] = 0.04;
66
67 // clang-format off
68 vols[0].push_back(Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.0091)));
69 vols[0].push_back(Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.0092)));
70 vols[1].push_back(Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.0070)));
71 vols[1].push_back(Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.0088)));
72 // clang-format on
73
74 // Create the optionlet surface
75 optionletSurface = QuantLib::ext::make_shared<StrippedOptionlet>(settlementDays, calendar, bdc, dummyIborIndex,
76 expiries, strikes, vols, dc, type);
77 }
78
79 ~F() {}
80};
81
82} // namespace
83BOOST_FIXTURE_TEST_SUITE(QuantExtTestSuite, TopLevelFixture)
84
85BOOST_AUTO_TEST_SUITE(StrippedOptionletAdapterTests)
86
87BOOST_FIXTURE_TEST_CASE(testFlatExtrapAfterLastExpiry, F) {
88
89 // Set up optionlet adapter with flat extrapolation
90 QuantLib::ext::shared_ptr<StrippedOptionletAdapter<LinearFlat, LinearFlat> > adapter =
91 QuantLib::ext::make_shared<StrippedOptionletAdapter<LinearFlat, LinearFlat> >(optionletSurface);
92
93 // Pick a date 1Y after the max date
94 Date testDate = expiries.back() + 1 * Years;
95
96 // Check flat extrapolation on the pillar strikes
97 for (Size i = 0; i < strikes.size(); i++) {
98 Volatility testVol = adapter->volatility(testDate, strikes[i], true);
99 BOOST_CHECK_CLOSE(testVol, vols.back()[i]->value(), 1e-12);
100 }
101
102 // Check flat extrapolation below first strike
103 Volatility testVol = adapter->volatility(testDate, strikes.front() / 2.0, true);
104 BOOST_CHECK_CLOSE(testVol, vols.back().front()->value(), 1e-12);
105
106 // Check flat extrapolation above last strike
107 testVol = adapter->volatility(testDate, 2.0 * strikes.back(), true);
108 BOOST_CHECK_CLOSE(testVol, vols.back().back()->value(), 1e-12);
109
110 // Check flat extrapolation between two strikes
111 Rate avgStrike = (strikes[0] + strikes[1]) / 2.0;
112 Volatility expectedVol = (vols.back()[0]->value() + vols.back()[1]->value()) / 2.0;
113 testVol = adapter->volatility(testDate, avgStrike, true);
114 BOOST_CHECK_CLOSE(testVol, expectedVol, 1e-12);
115}
116
117BOOST_FIXTURE_TEST_CASE(testFlatExtrapBetweenFirstLastExpiry, F) {
118
119 // Set up optionlet adapter with flat extrapolation
120 QuantLib::ext::shared_ptr<StrippedOptionletAdapter<LinearFlat, LinearFlat> > adapter =
121 QuantLib::ext::make_shared<StrippedOptionletAdapter<LinearFlat, LinearFlat> >(optionletSurface);
122
123 // Check flat extrapolation on expiry pillars
124 for (Size i = 0; i < expiries.size(); i++) {
125 // Below first strike
126 Volatility testVol = adapter->volatility(expiries[i], strikes.front() / 2.0, true);
127 BOOST_CHECK_CLOSE(testVol, vols[i].front()->value(), 1e-12);
128 // Above last strike
129 testVol = adapter->volatility(expiries[i], 2.0 * strikes.back(), true);
130 BOOST_CHECK_CLOSE(testVol, vols[i].back()->value(), 1e-12);
131 }
132
133 // Pick a date between first expiry and last expiry
134 Size numDays = dc.dayCount(expiries.front(), expiries.back()) / 2;
135 Date testDate = expiries.front() + numDays * Days;
136
137 // Check flat extrapolation below first strike
138 Volatility testVol = adapter->volatility(testDate, strikes.front() / 2.0, true);
139 Volatility expectedVol = adapter->volatility(testDate, strikes.front(), true);
140 BOOST_CHECK_CLOSE(testVol, expectedVol, 1e-12);
141
142 // Check flat extrapolation above last strike
143 testVol = adapter->volatility(testDate, 2.0 * strikes.back(), true);
144 expectedVol = adapter->volatility(testDate, strikes.back(), true);
145 BOOST_CHECK_CLOSE(testVol, expectedVol, 1e-12);
146}
147
148BOOST_FIXTURE_TEST_CASE(testFlatExtrapBeforeFirstExpiry, F) {
149
150 // Set up optionlet adapter with flat extrapolation
151 QuantLib::ext::shared_ptr<StrippedOptionletAdapter<LinearFlat, LinearFlat> > adapter =
152 QuantLib::ext::make_shared<StrippedOptionletAdapter<LinearFlat, LinearFlat> >(optionletSurface);
153
154 // Pick a date between evaluation date and first expiry
155 Size numDays = dc.dayCount(asof, expiries.front()) / 2;
156 Date testDate = asof + numDays * Days;
157
158 // Check flat extrapolation on the pillar strikes
159 for (Size i = 0; i < strikes.size(); i++) {
160 Volatility testVol = adapter->volatility(testDate, strikes[i], true);
161 BOOST_CHECK_CLOSE(testVol, vols.front()[i]->value(), 1e-12);
162 }
163
164 // Check flat extrapolation below first strike
165 Volatility testVol = adapter->volatility(testDate, strikes.front() / 2.0, true);
166 BOOST_CHECK_CLOSE(testVol, vols.front().front()->value(), 1e-12);
167
168 // Check flat extrapolation above last strike
169 testVol = adapter->volatility(testDate, 2.0 * strikes.back(), true);
170 BOOST_CHECK_CLOSE(testVol, vols.front().back()->value(), 1e-12);
171
172 // Check flat extrapolation between two strikes
173 Rate avgStrike = (strikes[0] + strikes[1]) / 2.0;
174 Volatility expectedVol = (vols.front()[0]->value() + vols.front()[1]->value()) / 2.0;
175 testVol = adapter->volatility(testDate, avgStrike, true);
176 BOOST_CHECK_CLOSE(testVol, expectedVol, 1e-12);
177}
178
179BOOST_AUTO_TEST_CASE(testOneStrikeColumn) {
180
181 BOOST_TEST_MESSAGE("Testing StrippedOptionletAdapter when StrippedOptionlet has one strike column");
182
183 // As of date
184 Date asof(17, Apr, 2019);
185 Settings::instance().evaluationDate() = asof;
186
187 // Set up the stripped optionlet surface with one strike column
188 Natural settlementDays = 2;
189 UnitedStates calendar(UnitedStates::Settlement);
190 BusinessDayConvention bdc = Following;
191 Actual365Fixed dc;
192 QuantLib::ext::shared_ptr<IborIndex> dummyIborIndex;
193 VolatilityType type = Normal;
194 vector<Date> expiries = list_of(Date(17, Jul, 2019))(Date(17, Oct, 2019));
195 vector<Rate> strikes = list_of(0.0);
196
197 vector<vector<Handle<Quote> > > vols(2);
198 vols[0].push_back(Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.0091)));
199 vols[1].push_back(Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.0070)));
200
201 // Create the optionlet surface
202 QuantLib::ext::shared_ptr<StrippedOptionlet> optionletSurface = QuantLib::ext::make_shared<StrippedOptionlet>(
203 settlementDays, calendar, bdc, dummyIborIndex, expiries, strikes, vols, dc, type);
204
205 // Set up optionlet adapter with flat extrapolation
206 QuantLib::ext::shared_ptr<StrippedOptionletAdapter<LinearFlat, LinearFlat> > adapter =
207 QuantLib::ext::make_shared<StrippedOptionletAdapter<LinearFlat, LinearFlat> >(optionletSurface);
208
209 // Ask for vols on expiry dates at any strikes and should get back inputs
210 Volatility strikeShift = 0.10;
211 Volatility testVol = adapter->volatility(expiries[0], 0.0, true);
212 Volatility expectedVol = vols[0][0]->value();
213 BOOST_CHECK_CLOSE(testVol, expectedVol, 1e-12);
214
215 testVol = adapter->volatility(expiries[0], 0.0 + strikeShift, true);
216 BOOST_CHECK_CLOSE(testVol, expectedVol, 1e-12);
217
218 testVol = adapter->volatility(expiries[0], 0.0 - strikeShift, true);
219 BOOST_CHECK_CLOSE(testVol, expectedVol, 1e-12);
220
221 testVol = adapter->volatility(expiries[0] - 1 * Weeks, 0.0, true);
222 BOOST_CHECK_CLOSE(testVol, expectedVol, 1e-12);
223
224 testVol = adapter->volatility(expiries[1], 0.0, true);
225 expectedVol = vols[1][0]->value();
226 BOOST_CHECK_CLOSE(testVol, expectedVol, 1e-12);
227
228 testVol = adapter->volatility(expiries[1] + 1 * Weeks, 0.0, true);
229 BOOST_CHECK_CLOSE(testVol, expectedVol, 1e-12);
230}
231
232BOOST_AUTO_TEST_SUITE_END()
233
234BOOST_AUTO_TEST_SUITE_END()
flat interpolation decorator
BOOST_FIXTURE_TEST_CASE(testFlatExtrapAfterLastExpiry, F)
BOOST_AUTO_TEST_CASE(testOneStrikeColumn)
Convert a StrippedOptionletBase in to an OptionletVolatilityStructure.
vector< Real > strikes
Fixture that can be used at top level.