105 {
106
107 BOOST_TEST_MESSAGE("Testing npv calculation in AnalyticEuropeanEngineDeltaGamma against QuantLib engine...");
108
109 TestData d;
110
111 Size n = d.pillarTimes.size();
112
113 Real strike = d.spot->value();
114 Date expiryDate = d.refDate + 6 * Years;
115 QuantLib::ext::shared_ptr<StrikedTypePayoff> payoff = QuantLib::ext::make_shared<PlainVanillaPayoff>(Option::Put, strike);
116 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<EuropeanExercise>(expiryDate);
117 QuantLib::ext::shared_ptr<VanillaOption> option = QuantLib::ext::make_shared<VanillaOption>(payoff, exercise);
118
119 QuantLib::ext::shared_ptr<PricingEngine> engine0 = QuantLib::ext::make_shared<AnalyticEuropeanEngine>(d.process);
120 QuantLib::ext::shared_ptr<PricingEngine> engine1 =
121 QuantLib::ext::make_shared<AnalyticEuropeanEngineDeltaGamma>(d.process, d.pillarTimes, d.pillarTimes, true, true);
122
123 option->setPricingEngine(engine0);
124 Real npv0 = option->NPV();
125
126 option->setPricingEngine(engine1);
127 Real npv = option->NPV();
128
129 Real tol = 1E-8;
130 if (std::fabs(npv0 - npv) > tol)
131 BOOST_ERROR("npv (" << npv << ") can not be verified, expected " << npv0);
132
133
134 Real deltaSpot = option->result<Real>("deltaSpot");
135 Real gammaSpot = option->result<Real>("gammaSpot");
136
137 std::vector<Real> vega = option->result<std::vector<Real>>("vega");
138 std::vector<Real> deltaRate = option->result<std::vector<Real>>("deltaRate");
139 std::vector<Real> deltaDividend = option->result<std::vector<Real>>("deltaDividend");
140 Matrix gamma = option->result<Matrix>("gamma");
141 std::vector<Real> gammaSpotRate = option->result<std::vector<Real>>("gammaSpotRate");
142 std::vector<Real> gammaSpotDiv = option->result<std::vector<Real>>("gammaSpotDiv");
143
144
145 option->setPricingEngine(engine0);
146
147
148
149 BOOST_TEST_MESSAGE("Checking additional results for correct dimensions in AnalyticEuropeanEngineDeltaGamma...");
150
151 if (vega.size() != n)
152 BOOST_ERROR("vega size (" << vega.size() << ") mismatch, expected " << n);
153 if (deltaRate.size() != n)
154 BOOST_ERROR("delta rate size (" << deltaRate.size() << ") mismatch, expected " << n);
155 if (deltaDividend.size() != n)
156 BOOST_ERROR("delta dividend size (" << deltaDividend.size() << ") mismatch, expected " << n);
157 if (gamma.rows() != 2 * n || gamma.columns() != 2 * n)
158 BOOST_ERROR("gamma size (" << gamma.rows() << "x" << gamma.columns() << ") mismatch, expected " << 2 * n << "x"
159 << 2 * n);
160 if (gammaSpotRate.size() != n)
161 BOOST_ERROR("gamma spot rate size (" << gammaSpotRate.size() << ") mismatch, expected " << n);
162 if (gammaSpotDiv.size() != n)
163 BOOST_ERROR("gamma spot div size (" << gammaSpotDiv.size() << ") mismatch, expected " << n);
164
165
166
167 BOOST_TEST_MESSAGE(
168 "Checking additional results against bump and revalue results in AnalyticEuropeanEngineDeltaGamma...");
169
170 Real h1 = 1E-4;
171 Real h2 = 1E-6;
172
173 d.spot->setValue(d.spot->value() + h1);
174 Real npvp = option->NPV();
175 d.spot->setValue(d.spot->value() - 2.0 * h1);
176 Real npvm = option->NPV();
177 d.spot->setValue(d.spot->value() + h1);
178
179 Real refDelta = (npvp - npvm) / (2.0 * h1);
180 Real refGamma = (npvp - 2.0 * npv + npvm) / (h1 * h1);
181
182 if (!
check(refDelta, deltaSpot))
183 BOOST_ERROR("could not verify delta (reference value=" << refDelta << ", result=" << deltaSpot
184 << ", difference=" << deltaSpot - refDelta << ")");
185 if (!
check(refGamma, gammaSpot))
186 BOOST_ERROR("could not verify gamma (reference value=" << refGamma << ", result=" << gammaSpot
187 << ", difference=" << gammaSpot - refGamma << ")");
188
189
190
191
192
193
194
195
196 Real vegaSum = 0.0;
197 for (Size i = 0; i < vega.size(); ++i) {
198 vegaSum += vega[i];
199 }
200
201 d.vol->setValue(d.vol->value() + h2);
202 Real npvvp = option->NPV();
203 d.vol->setValue(d.vol->value() - h2);
204 Real refVega = (npvvp - npv) / h2;
205
206 if (!
check(refVega, vegaSum))
207 BOOST_ERROR("could not verify vega (reference value=" << refVega << ", result=" << vegaSum
208 << ", difference=" << vegaSum - refVega << ")");
209
210 for (Size i = 0; i < n; ++i) {
211 d.rateSpreads[i]->setValue(h2);
212 Real refDeltaRate = (option->NPV() - npv) / h2;
213 d.rateSpreads[i]->setValue(0.0);
214 d.divSpreads[i]->setValue(h2);
215 Real refDeltaDiv = (option->NPV() - npv) / h2;
216 d.divSpreads[i]->setValue(0.0);
217 if (!
check(refDeltaRate, deltaRate[i]))
218 BOOST_ERROR("delta on pillar " << d.pillarTimes[i] << " (rate curve) could not be verified, analytical: "
219 << deltaRate[i] << ", bump and revalue: " << refDeltaRate);
220 if (!
check(refDeltaDiv, deltaDividend[i]))
221 BOOST_ERROR("delta on pillar " << d.pillarTimes[i]
222 << " (dividend curve) could not be verified, analytical: "
223 << deltaDividend[i] << ", bump and revalue: " << refDeltaDiv);
224 }
225
226 Matrix refGammaRateDiv(n * 2, n * 2, 0.0);
227
228
229 for (Size i = 0; i < n; ++i) {
230
231 for (Size j = 0; j < i; ++j) {
232 d.rateSpreads[i]->setValue(h1);
233 d.rateSpreads[j]->setValue(h1);
234 Real npvpp = option->NPV();
235 d.rateSpreads[j]->setValue(0.0);
236 Real npvp0 = option->NPV();
237 d.rateSpreads[i]->setValue(0.0);
238 d.rateSpreads[j]->setValue(h1);
239 Real npv0p = option->NPV();
240 d.rateSpreads[j]->setValue(0.0);
241 Real gamma = (npvpp - npvp0 - npv0p + npv) / (h1 * h1);
242 refGammaRateDiv[i][j] = refGammaRateDiv[j][i] = gamma;
243 }
244
245 d.rateSpreads[i]->setValue(2.0 * h1);
246 Real npvpp = option->NPV();
247 d.rateSpreads[i]->setValue(h1);
248 Real npvp = option->NPV();
249 d.rateSpreads[i]->setValue(0.0);
250 Real gamma = (npvpp - 2.0 * npvp + npv) / (h1 * h1);
251 refGammaRateDiv[i][i] = gamma;
252 }
253
254
255 for (Size i = 0; i < n; ++i) {
256
257 for (Size j = 0; j < n; ++j) {
258 d.rateSpreads[i]->setValue(h1);
259 d.divSpreads[j]->setValue(h1);
260 Real npvpp = option->NPV();
261 d.divSpreads[j]->setValue(0.0);
262 Real npvp0 = option->NPV();
263 d.rateSpreads[i]->setValue(0.0);
264 d.divSpreads[j]->setValue(h1);
265 Real npv0p = option->NPV();
266 d.divSpreads[j]->setValue(0.0);
267 Real gamma = (npvpp - npvp0 - npv0p + npv) / (h1 * h1);
268 refGammaRateDiv[i][n + j] = refGammaRateDiv[n + j][i] = gamma;
269 }
270 }
271
272
273 for (Size i = 0; i < n; ++i) {
274
275 for (Size j = 0; j < i; ++j) {
276 d.divSpreads[i]->setValue(h1);
277 d.divSpreads[j]->setValue(h1);
278 Real npvpp = option->NPV();
279 d.divSpreads[j]->setValue(0.0);
280 Real npvp0 = option->NPV();
281 d.divSpreads[i]->setValue(0.0);
282 d.divSpreads[j]->setValue(h1);
283 Real npv0p = option->NPV();
284 d.divSpreads[j]->setValue(0.0);
285 Real gamma = (npvpp - npvp0 - npv0p + npv) / (h1 * h1);
286 refGammaRateDiv[n + i][n + j] = refGammaRateDiv[n + j][n + i] = gamma;
287 }
288
289 d.divSpreads[i]->setValue(2.0 * h1);
290 Real npvpp = option->NPV();
291 d.divSpreads[i]->setValue(h1);
292 Real npvp = option->NPV();
293 d.divSpreads[i]->setValue(0.0);
294 Real gamma = (npvpp - 2.0 * npvp + npv0) / (h1 * h1);
295 refGammaRateDiv[n + i][n + i] = gamma;
296 }
297
298 for (Size i = 0; i < 2 * n; ++i) {
299 for (Size j = 0; j < 2 * n; ++j) {
300 if (!
check(refGammaRateDiv[i][j], gamma[i][j]))
301 BOOST_ERROR("gamma entry (" << i << "," << j << ") is " << gamma[i][j]
302 << ", bump and revalue result is " << refGammaRateDiv[i][j]);
303 }
304 }
305
306
307 for (Size i = 0; i < n; ++i) {
308 d.spot->setValue(d.spot->value() + h1);
309 d.rateSpreads[i]->setValue(h1);
310 Real npvpp = option->NPV();
311 d.rateSpreads[i]->setValue(0.0);
312 Real npvp0 = option->NPV();
313 d.spot->setValue(d.spot->value() - h1);
314 d.rateSpreads[i]->setValue(h1);
315 Real npv0p = option->NPV();
316 d.rateSpreads[i]->setValue(0.0);
317 Real refGamma = (npvpp - npvp0 - npv0p + npv) / (h1 * h1);
318 if (!
check(refGamma, gammaSpotRate[i]))
319 BOOST_ERROR("spot-rate gamma pillar " << i << " can not be verified, result is " << gammaSpotRate[i]
320 << ", bump and revalue is " << refGamma);
321 }
322
323
324 for (Size i = 0; i < n; ++i) {
325 d.spot->setValue(d.spot->value() + h1);
326 d.divSpreads[i]->setValue(h1);
327 Real npvpp = option->NPV();
328 d.divSpreads[i]->setValue(0.0);
329 Real npvp0 = option->NPV();
330 d.spot->setValue(d.spot->value() - h1);
331 d.divSpreads[i]->setValue(h1);
332 Real npv0p = option->NPV();
333 d.divSpreads[i]->setValue(0.0);
334 Real refGamma = (npvpp - npvp0 - npv0p + npv) / (h1 * h1);
335 if (!
check(refGamma, gammaSpotDiv[i]))
336 BOOST_ERROR("spot-div gamma pillar " << i << " can not be verified, result is " << gammaSpotDiv[i]
337 << ", bump and revalue is " << refGamma);
338 }
339
340 BOOST_CHECK(true);
341
342}