21#include <boost/test/unit_test.hpp>
25#include <ql/math/matrix.hpp>
26#include <ql/quotes/simplequote.hpp>
27#include <ql/termstructures/volatility/equityfx/blackvariancesurface.hpp>
28#include <ql/termstructures/yield/flatforward.hpp>
29#include <ql/time/calendars/target.hpp>
33using namespace boost::unit_test_framework;
39 TestData() : origRefDate(20, Jan, 2016) {
41 Settings::instance().evaluationDate() = origRefDate;
44 refDates.push_back(TARGET().advance(origRefDate, 1 * Years));
45 refDates.push_back(TARGET().advance(origRefDate, 2 * Years));
58 refVol = Handle<BlackVolTermStructure>(
59 QuantLib::ext::make_shared<BlackVarianceSurface>(origRefDate, TARGET(), refDates,
strikes, vol, Actual365Fixed()));
60 refVol->enableExtrapolation();
63 spot = QuantLib::ext::make_shared<SimpleQuote>(1.00);
64 spot_q = Handle<Quote>(spot);
65 rate = QuantLib::ext::make_shared<SimpleQuote>(0.02);
66 rate_q = Handle<Quote>(rate);
67 div = QuantLib::ext::make_shared<SimpleQuote>(0.02);
68 div_q = Handle<Quote>(div);
70 riskfreeTs = Handle<YieldTermStructure>(QuantLib::ext::make_shared<FlatForward>(0, TARGET(), rate_q, Actual365Fixed()));
71 dividendTs = Handle<YieldTermStructure>(QuantLib::ext::make_shared<FlatForward>(0, TARGET(), div_q, Actual365Fixed()));
75 const Date origRefDate;
76 std::vector<Date> refDates;
79 Handle<BlackVolTermStructure> refVol;
80 QuantLib::ext::shared_ptr<SimpleQuote> spot, rate, div;
81 Handle<Quote> spot_q, rate_q, div_q;
82 Handle<YieldTermStructure> riskfreeTs, dividendTs;
89BOOST_AUTO_TEST_SUITE(DynamicBlackVolTermStructureTest)
93 BOOST_TEST_MESSAGE(
"Testing constant variance, sticky strike dynamics of "
94 "DynamicBlackVolTermStructure...");
98 Handle<DynamicBlackVolTermStructure<tag::surface> > dyn(
102 dyn->enableExtrapolation();
108 BOOST_CHECK_CLOSE(dyn->blackVol(0.5, 0.80), d.refVol->blackVol(0.5, 0.80), tol);
109 BOOST_CHECK_CLOSE(dyn->blackVol(0.5, 0.90), d.refVol->blackVol(0.5, 0.90), tol);
110 BOOST_CHECK_CLOSE(dyn->blackVol(0.5, 0.95), d.refVol->blackVol(0.5, 0.95), tol);
111 BOOST_CHECK_CLOSE(dyn->blackVol(0.5, 1.15), d.refVol->blackVol(0.5, 1.15), tol);
113 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.80), d.refVol->blackVol(1.5, 0.80), tol);
114 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.90), d.refVol->blackVol(1.5, 0.90), tol);
115 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.95), d.refVol->blackVol(1.5, 0.95), tol);
116 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 1.15), d.refVol->blackVol(1.5, 1.15), tol);
118 BOOST_CHECK_CLOSE(dyn->blackVol(5.0, 0.80), d.refVol->blackVol(5.0, 0.80), tol);
119 BOOST_CHECK_CLOSE(dyn->blackVol(5.0, 0.90), d.refVol->blackVol(5.0, 0.90), tol);
120 BOOST_CHECK_CLOSE(dyn->blackVol(5.0, 0.95), d.refVol->blackVol(5.0, 0.95), tol);
121 BOOST_CHECK_CLOSE(dyn->blackVol(5.0, 1.15), d.refVol->blackVol(5.0, 1.15), tol);
125 BOOST_CHECK_CLOSE(dyn->blackVol(0.5, Null<Real>()), d.refVol->blackVol(0.5, d.spot->value()), tol);
126 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, Null<Real>()), d.refVol->blackVol(1.5, d.spot->value()), tol);
127 BOOST_CHECK_CLOSE(dyn->blackVol(5.0, Null<Real>()), d.refVol->blackVol(5.0, d.spot->value()), tol);
132 Settings::instance().evaluationDate() = TARGET().advance(d.origRefDate, 6 * Months);
133 d.spot->setValue(0.9);
134 BOOST_CHECK_CLOSE(dyn->blackVol(0.7, 0.80), d.refVol->blackVol(0.7, 0.80), tol);
135 BOOST_CHECK_CLOSE(dyn->blackVol(0.7, 0.90), d.refVol->blackVol(0.7, 0.90), tol);
136 BOOST_CHECK_CLOSE(dyn->blackVol(0.7, 0.95), d.refVol->blackVol(0.7, 0.95), tol);
137 BOOST_CHECK_CLOSE(dyn->blackVol(0.7, 1.15), d.refVol->blackVol(0.7, 1.15), tol);
139 Settings::instance().evaluationDate() = TARGET().advance(d.origRefDate, 18 * Months);
140 d.rate->setValue(0.01);
141 BOOST_CHECK_CLOSE(dyn->blackVol(1.7, 0.80), d.refVol->blackVol(1.7, 0.80), tol);
142 BOOST_CHECK_CLOSE(dyn->blackVol(1.7, 0.90), d.refVol->blackVol(1.7, 0.90), tol);
143 BOOST_CHECK_CLOSE(dyn->blackVol(1.7, 0.95), d.refVol->blackVol(1.7, 0.95), tol);
144 BOOST_CHECK_CLOSE(dyn->blackVol(1.7, 1.15), d.refVol->blackVol(1.7, 1.15), tol);
146 Settings::instance().evaluationDate() = TARGET().advance(d.origRefDate, 3 * Years);
147 d.div->setValue(0.03);
148 BOOST_CHECK_CLOSE(dyn->blackVol(1.71, 0.80), d.refVol->blackVol(1.71, 0.80), tol);
149 BOOST_CHECK_CLOSE(dyn->blackVol(1.71, 0.90), d.refVol->blackVol(1.71, 0.90), tol);
150 BOOST_CHECK_CLOSE(dyn->blackVol(1.71, 0.95), d.refVol->blackVol(1.71, 0.95), tol);
151 BOOST_CHECK_CLOSE(dyn->blackVol(1.71, 1.15), d.refVol->blackVol(1.71, 1.15), tol);
157 BOOST_TEST_MESSAGE(
"Testing constant variance, sticky log-moneyness "
158 "dynamics of DynamicBlackVolTermStructure...");
162 Handle<DynamicBlackVolTermStructure<tag::surface> > dyn(
166 dyn->enableExtrapolation();
172 BOOST_CHECK_CLOSE(dyn->blackVol(0.5, 0.80), d.refVol->blackVol(0.5, 0.80), tol);
173 BOOST_CHECK_CLOSE(dyn->blackVol(0.5, 0.90), d.refVol->blackVol(0.5, 0.90), tol);
174 BOOST_CHECK_CLOSE(dyn->blackVol(0.5, 0.95), d.refVol->blackVol(0.5, 0.95), tol);
175 BOOST_CHECK_CLOSE(dyn->blackVol(0.5, 1.15), d.refVol->blackVol(0.5, 1.15), tol);
177 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.80), d.refVol->blackVol(1.5, 0.80), tol);
178 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.90), d.refVol->blackVol(1.5, 0.90), tol);
179 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.95), d.refVol->blackVol(1.5, 0.95), tol);
180 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 1.15), d.refVol->blackVol(1.5, 1.15), tol);
182 BOOST_CHECK_CLOSE(dyn->blackVol(5.0, 0.80), d.refVol->blackVol(5.0, 0.80), tol);
183 BOOST_CHECK_CLOSE(dyn->blackVol(5.0, 0.90), d.refVol->blackVol(5.0, 0.90), tol);
184 BOOST_CHECK_CLOSE(dyn->blackVol(5.0, 0.95), d.refVol->blackVol(5.0, 0.95), tol);
185 BOOST_CHECK_CLOSE(dyn->blackVol(5.0, 1.15), d.refVol->blackVol(5.0, 1.15), tol);
191 Settings::instance().evaluationDate() = TARGET().advance(d.origRefDate, 6 * Months);
193 Real atm0 = d.spot->value();
194 d.spot->setValue(0.9);
195 Real atm = d.spot->value();
197 BOOST_CHECK_CLOSE(dyn->blackVol(0.7, atm * std::exp(-0.25)), d.refVol->blackVol(0.7, atm0 * std::exp(-0.25)), tol);
198 BOOST_CHECK_CLOSE(dyn->blackVol(0.7, atm * std::exp(0.00)), d.refVol->blackVol(0.7, atm0 * std::exp(0.00)), tol);
199 BOOST_CHECK_CLOSE(dyn->blackVol(0.7, atm * std::exp(0.25)), d.refVol->blackVol(0.7, atm0 * std::exp(0.25)), tol);
201 BOOST_CHECK_CLOSE(dyn->blackVol(1.7, atm * std::exp(-0.25)), d.refVol->blackVol(1.7, atm0 * std::exp(-0.25)), tol);
202 BOOST_CHECK_CLOSE(dyn->blackVol(1.7, atm * std::exp(0.00)), d.refVol->blackVol(1.7, atm0 * std::exp(0.00)), tol);
203 BOOST_CHECK_CLOSE(dyn->blackVol(1.7, atm * std::exp(0.25)), d.refVol->blackVol(1.7, atm0 * std::exp(0.25)), tol);
205 BOOST_CHECK_CLOSE(dyn->blackVol(3.0, atm * std::exp(-0.25)), d.refVol->blackVol(3.0, atm0 * std::exp(-0.25)), tol);
206 BOOST_CHECK_CLOSE(dyn->blackVol(3.0, atm * std::exp(0.00)), d.refVol->blackVol(3.0, atm0 * std::exp(0.00)), tol);
207 BOOST_CHECK_CLOSE(dyn->blackVol(3.0, atm * std::exp(0.25)), d.refVol->blackVol(3.0, atm0 * std::exp(0.25)), tol);
209 Settings::instance().evaluationDate() = TARGET().advance(d.origRefDate, 18 * Months);
210 d.rate->setValue(0.01);
212 atm = d.spot->value() / d.riskfreeTs->discount(1.8) * d.dividendTs->discount(1.8);
214 BOOST_CHECK_CLOSE(dyn->blackVol(1.8, atm * std::exp(-0.25)), d.refVol->blackVol(1.8, atm0 * std::exp(-0.25)), tol);
215 BOOST_CHECK_CLOSE(dyn->blackVol(1.8, atm * std::exp(0.00)), d.refVol->blackVol(1.8, atm0 * std::exp(0.00)), tol);
216 BOOST_CHECK_CLOSE(dyn->blackVol(1.8, atm * std::exp(0.25)), d.refVol->blackVol(1.8, atm0 * std::exp(0.25)), tol);
218 Settings::instance().evaluationDate() = TARGET().advance(d.origRefDate, 3 * Years);
219 d.div->setValue(0.03);
221 atm = d.spot->value() / d.riskfreeTs->discount(3.5) * d.dividendTs->discount(3.5);
223 BOOST_CHECK_CLOSE(dyn->blackVol(3.5, atm * std::exp(-0.25)), d.refVol->blackVol(3.5, atm0 * std::exp(-0.25)), tol);
224 BOOST_CHECK_CLOSE(dyn->blackVol(3.5, atm * std::exp(0.00)), d.refVol->blackVol(3.5, atm0 * std::exp(0.00)), tol);
225 BOOST_CHECK_CLOSE(dyn->blackVol(3.5, atm * std::exp(0.25)), d.refVol->blackVol(3.5, atm0 * std::exp(0.25)), tol);
231 BOOST_TEST_MESSAGE(
"Testing forward-forward variance, sticky strike "
232 "dynamics of DynamicBlackVolTermStructure...");
236 Handle<DynamicBlackVolTermStructure<tag::surface> > dyn(
240 dyn->enableExtrapolation();
246 BOOST_CHECK_CLOSE(dyn->blackVol(0.5, 0.80), d.refVol->blackVol(0.5, 0.80), tol);
247 BOOST_CHECK_CLOSE(dyn->blackVol(0.5, 0.90), d.refVol->blackVol(0.5, 0.90), tol);
248 BOOST_CHECK_CLOSE(dyn->blackVol(0.5, 0.95), d.refVol->blackVol(0.5, 0.95), tol);
249 BOOST_CHECK_CLOSE(dyn->blackVol(0.5, 1.15), d.refVol->blackVol(0.5, 1.15), tol);
251 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.80), d.refVol->blackVol(1.5, 0.80), tol);
252 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.90), d.refVol->blackVol(1.5, 0.90), tol);
253 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.95), d.refVol->blackVol(1.5, 0.95), tol);
254 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 1.15), d.refVol->blackVol(1.5, 1.15), tol);
256 BOOST_CHECK_CLOSE(dyn->blackVol(5.0, 0.80), d.refVol->blackVol(5.0, 0.80), tol);
257 BOOST_CHECK_CLOSE(dyn->blackVol(5.0, 0.90), d.refVol->blackVol(5.0, 0.90), tol);
258 BOOST_CHECK_CLOSE(dyn->blackVol(5.0, 0.95), d.refVol->blackVol(5.0, 0.95), tol);
259 BOOST_CHECK_CLOSE(dyn->blackVol(5.0, 1.15), d.refVol->blackVol(5.0, 1.15), tol);
265 Settings::instance().evaluationDate() = TARGET().advance(d.origRefDate, 6 * Months);
266 Real t = d.refVol->timeFromReference(Settings::instance().evaluationDate());
267 d.spot->setValue(0.9);
269 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.80), d.refVol->blackForwardVol(t, t + 1.5, 0.80), tol);
270 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.90), d.refVol->blackForwardVol(t, t + 1.5, 0.90), tol);
271 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.95), d.refVol->blackForwardVol(t, t + 1.5, 0.95), tol);
272 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 1.15), d.refVol->blackForwardVol(t, t + 1.5, 1.15), tol);
274 Settings::instance().evaluationDate() = TARGET().advance(d.origRefDate, 18 * Months);
275 t = d.refVol->timeFromReference(Settings::instance().evaluationDate());
276 d.rate->setValue(0.01);
278 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.80), d.refVol->blackForwardVol(t, t + 1.5, 0.80), tol);
279 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.90), d.refVol->blackForwardVol(t, t + 1.5, 0.90), tol);
280 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.95), d.refVol->blackForwardVol(t, t + 1.5, 0.95), tol);
281 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 1.15), d.refVol->blackForwardVol(t, t + 1.5, 1.15), tol);
283 Settings::instance().evaluationDate() = TARGET().advance(d.origRefDate, 3 * Years);
284 t = d.refVol->timeFromReference(Settings::instance().evaluationDate());
285 d.div->setValue(0.03);
287 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.80), d.refVol->blackForwardVol(t, t + 1.5, 0.80), tol);
288 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.90), d.refVol->blackForwardVol(t, t + 1.5, 0.90), tol);
289 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.95), d.refVol->blackForwardVol(t, t + 1.5, 0.95), tol);
290 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 1.15), d.refVol->blackForwardVol(t, t + 1.5, 1.15), tol);
296 BOOST_TEST_MESSAGE(
"Testing forward-forward variance, sticky log-moneyness "
297 "dynamics of DynamicBlackVolTermStructure...");
301 Handle<DynamicBlackVolTermStructure<tag::surface> > dyn(
305 dyn->enableExtrapolation();
311 BOOST_CHECK_CLOSE(dyn->blackVol(0.5, 0.80), d.refVol->blackVol(0.5, 0.80), tol);
312 BOOST_CHECK_CLOSE(dyn->blackVol(0.5, 0.90), d.refVol->blackVol(0.5, 0.90), tol);
313 BOOST_CHECK_CLOSE(dyn->blackVol(0.5, 0.95), d.refVol->blackVol(0.5, 0.95), tol);
314 BOOST_CHECK_CLOSE(dyn->blackVol(0.5, 1.15), d.refVol->blackVol(0.5, 1.15), tol);
316 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.80), d.refVol->blackVol(1.5, 0.80), tol);
317 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.90), d.refVol->blackVol(1.5, 0.90), tol);
318 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 0.95), d.refVol->blackVol(1.5, 0.95), tol);
319 BOOST_CHECK_CLOSE(dyn->blackVol(1.5, 1.15), d.refVol->blackVol(1.5, 1.15), tol);
321 BOOST_CHECK_CLOSE(dyn->blackVol(5.0, 0.80), d.refVol->blackVol(5.0, 0.80), tol);
322 BOOST_CHECK_CLOSE(dyn->blackVol(5.0, 0.90), d.refVol->blackVol(5.0, 0.90), tol);
323 BOOST_CHECK_CLOSE(dyn->blackVol(5.0, 0.95), d.refVol->blackVol(5.0, 0.95), tol);
324 BOOST_CHECK_CLOSE(dyn->blackVol(5.0, 1.15), d.refVol->blackVol(5.0, 1.15), tol);
330 Settings::instance().evaluationDate() = TARGET().advance(d.origRefDate, 18 * Months);
331 Real t = d.refVol->timeFromReference(Settings::instance().evaluationDate());
332 Real atm0 = d.spot->value();
333 d.spot->setValue(0.9);
334 Real atm = d.spot->value();
336 BOOST_CHECK_CLOSE(dyn->blackVariance(1.5, atm * std::exp(-0.25)),
337 d.refVol->blackVariance(t + 1.5, atm0 * std::exp(-0.25)) -
338 d.refVol->blackVariance(t, atm0 * std::exp(-0.25)),
341 dyn->blackVariance(1.5, atm * std::exp(0.0)),
342 d.refVol->blackVariance(t + 1.5, atm0 * std::exp(0.0)) - d.refVol->blackVariance(t, atm0 * std::exp(0.0)), tol);
343 BOOST_CHECK_CLOSE(dyn->blackVariance(1.5, atm * std::exp(0.25)),
344 d.refVol->blackVariance(t + 1.5, atm0 * std::exp(0.25)) -
345 d.refVol->blackVariance(t, atm0 * std::exp(0.25)),
349BOOST_AUTO_TEST_SUITE_END()
351BOOST_AUTO_TEST_SUITE_END()
Takes a BlackVolTermStructure with fixed reference date and turns it into a floating reference date t...
BOOST_AUTO_TEST_CASE(testConstantVarianceStickyStrike)
dynamic black volatility term structure
Fixture that can be used at top level.
helper macros and methods for tests