35 {
36
37 BOOST_TEST_MESSAGE("Testing QuantExt::BlackVarianceSurfaceSparse with market data...");
38
39 SavedSettings backup;
40
41
42
43
44
45 Settings::instance().evaluationDate() = Date(1, Mar, 2010);
46 Date today = Settings::instance().evaluationDate();
47
48 Real spot = 2772.70;
49
50
51 vector<Time> all_times({ 0.025, 0.101, 0.197, 0.274, 0.523, 0.772, 1.769, 2.267, 2.784, 3.781, 4.778, 5.774 });
52
53
54
55
56 vector<vector<Real> > volData(
57 { { 51.31, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 33.66, 32.91 },
58 { 58.64, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 31.78, 31.29, 30.08 },
59 { 65.97, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 30.19, 29.76, 29.75 },
60 { 73.30, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 28.63, 28.48, 28.48 },
61 { 76.97, 00.00, 00.00, 00.00, 32.62, 30.79, 30.01, 28.43 },
62 { 80.63, 00.00, 00.00, 00.00, 30.58, 29.36, 28.76, 27.53, 27.13, 27.11, 27.11, 27.22, 28.09 },
63 { 84.30, 00.00, 00.00, 00.00, 28.87, 27.98, 27.50, 26.66 },
64 { 86.13, 33.65 },
65 { 87.96, 32.16, 29.06, 27.64, 27.17, 26.63, 26.37, 25.75, 25.55, 25.80, 25.85, 26.11, 26.93 },
66 { 89.79, 30.43, 27.97, 26.72 },
67 { 91.63, 28.80, 26.90, 25.78, 25.57, 25.31, 25.19, 24.97 },
68 { 93.46, 27.24, 25.90, 24.89 },
69 { 95.29, 25.86, 24.88, 24.05, 24.07, 24.04, 24.11, 24.18, 24.10, 24.48, 24.69, 25.01, 25.84 },
70 { 97.12, 24.66, 23.90, 23.29 },
71 { 98.96, 23.58, 23.00, 22.53, 22.69, 22.84, 22.99, 23.47 },
72 { 100.79, 22.47, 22.13, 21.84 },
73 { 102.62, 21.59, 21.40, 21.23, 21.42, 21.73, 21.98, 22.83, 22.75, 23.22, 23.84, 23.92, 24.86 },
74 { 104.45, 20.91, 20.76, 20.69 },
75 { 106.29, 20.56, 20.24, 20.25, 20.39, 20.74, 21.04, 22.13 },
76 { 108.12, 20.45, 19.82, 19.84 },
77 { 109.95, 20.25, 19.59, 19.44, 19.62, 19.88, 20.22, 21.51, 21.61, 22.19, 22.69, 23.05, 23.99 },
78 { 111.78, 19.33, 19.29, 19.20 },
79 { 113.62, 00.00, 00.00, 00.00, 19.02, 19.14, 19.50, 20.91 },
80 { 117.28, 00.00, 00.00, 00.00, 18.85, 18.54, 18.88, 20.39, 20.58, 21.22, 21.86, 22.23, 23.21 },
81 { 120.95, 00.00, 00.00, 00.00, 18.67, 18.11, 18.39, 19.90 },
82 { 124.61, 00.00, 00.00, 00.00, 18.71, 17.85, 17.93, 19.45, 00.00, 20.54, 21.03, 21.64, 22.51 },
83 { 131.94, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 19.88, 20.54, 21.05, 21.90 },
84 { 139.27, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 19.30, 20.02, 20.54, 21.35 },
85 { 146.60, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 00.00, 18.49, 19.64, 20.12 } });
86
87
88 vector<Date> dates;
90 vector<Volatility> vols;
91
92
93 for (auto vd : volData) {
94 Real strike = spot * vd[0];
95 for (Size i = 1; i < vd.size(); i++) {
96 Volatility vol = vd[i] / 100.0;
97 if (vol > 0.0001) {
98 Date d = today + int(all_times[i - 1] * 365);
99
100 dates.push_back(d);
102 vols.push_back(vol);
103 }
104 }
105 }
106
107 Calendar cal = TARGET();
108 DayCounter dc = ActualActual(ActualActual::ISDA);
109
110 auto surface = QuantLib::ext::make_shared<QuantExt::BlackVarianceSurfaceSparse>(today, cal, dates,
strikes, vols, dc);
111
112
113 for (auto vd : volData) {
114 Real strike = spot * vd[0];
115 for (Size i = 1; i < vd.size(); i++) {
116 Volatility expectedVol = vd[i] / 100.0;
117 if (expectedVol > 0.0001) {
118 Date d = today + int(all_times[i - 1] * 365);
119 Volatility vol = surface->blackVol(d, strike);
120 BOOST_CHECK_CLOSE(vol, expectedVol, 1e-12);
121 }
122 }
123 }
124
125
126 vector<Real> all_strikes;
127 vector<Date> all_dates;
128 for (auto vd : volData)
129 all_strikes.push_back(spot * vd[0]);
130 for (auto t : all_times)
131 all_dates.push_back(today + int(t * 365));
132
133 for (auto strike : all_strikes) {
134 for (auto d : all_dates)
135 BOOST_CHECK(surface->blackVol(d, strike) > 0.0001);
136 for (auto t : all_times)
137 BOOST_CHECK(surface->blackVol(t, strike) > 0.0001);
138 }
139}