QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
sensitivityanalysis.cpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2008 Ferdinando Ametrano
5
6 This file is part of QuantLib, a free-software/open-source library
7 for financial quantitative analysts and developers - http://quantlib.org/
8
9 QuantLib is free software: you can redistribute it and/or modify it
10 under the terms of the QuantLib license. You should have received a
11 copy of the license along with this program; if not, please email
12 <quantlib-dev@lists.sf.net>. The license is also available online at
13 <http://quantlib.org/license.shtml>.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the license for more details.
18*/
19
20#include <ql/experimental/risk/sensitivityanalysis.hpp>
21#include <ql/quotes/simplequote.hpp>
22#include <ql/instrument.hpp>
23
24using std::vector;
25using std::pair;
26
27namespace QuantLib {
28
29 std::ostream& operator<<(std::ostream& out,
31 switch (s) {
32 case OneSide:
33 return out << "OneSide";
34 case Centered:
35 return out << "Centered";
36 default:
37 QL_FAIL("unknown SensitivityAnalysis (" << Integer(s) << ")");
38 }
39 }
40
41 Real aggregateNPV(const vector<ext::shared_ptr<Instrument> >& instruments,
42 const vector<Real>& quant) {
43 Size n = instruments.size();
44 Real npv = 0.0;
45 if (quant.empty() || (quant.size()==1 && quant[0]==1.0)) {
46 for (Size k=0; k<n; ++k)
47 npv += instruments[k]->NPV();
48 } else {
49 QL_REQUIRE(quant.size()==n,
50 "dimension mismatch between instruments (" << n <<
51 ") and quantities (" << quant.size() << ")");
52 for (Size k=0; k<n; ++k)
53 npv += quant[k] * instruments[k]->NPV();
54 }
55 return npv;
56 }
57
58 pair<Real, Real>
59 parallelAnalysis(const vector<Handle<SimpleQuote> >& quotes,
60 const vector<ext::shared_ptr<Instrument> >& instruments,
61 const vector<Real>& quantities,
62 Real shift,
64 Real referenceNpv)
65 {
66 QL_REQUIRE(!quotes.empty(), "empty SimpleQuote vector");
67 Size n = quotes.size();
68
69 QL_REQUIRE(shift!=0.0, "zero shift not allowed");
70
71 pair<Real, Real> result(0.0, 0.0);
72 if (instruments.empty()) return result;
73
74 if (referenceNpv==Null<Real>())
75 referenceNpv = aggregateNPV(instruments, quantities);
76
77 vector<Real> quoteValues(n, Null<Real>());
78 for (Size i=0; i<n; ++i)
79 if (quotes[i]->isValid())
80 quoteValues[i] = quotes[i]->value();
81 try {
82 for (Size i=0; i<n; ++i)
83 if (quotes[i]->isValid())
84 quotes[i]->setValue(quoteValues[i]+shift);
85 Real npv = aggregateNPV(instruments, quantities);
86 switch (type) {
87 case OneSide:
88 result.first = (npv-referenceNpv)/shift;
89 result.second = Null<Real>();
90 break;
91 case Centered:
92 {
93 for (Size i=0; i<n; ++i)
94 if (quotes[i]->isValid())
95 quotes[i]->setValue(quoteValues[i]-shift);
96 Real npv2 = aggregateNPV(instruments, quantities);
97 result.first = (npv-npv2)/(2.0*shift);
98 result.second = (npv-2.0*referenceNpv+npv2)/(shift*shift);
99 }
100 break;
101 default:
102 QL_FAIL("unknown SensitivityAnalysis (" <<
103 Integer(type) << ")");
104 }
105 for (Size i=0; i<n; ++i)
106 if (quotes[i]->isValid())
107 quotes[i]->setValue(quoteValues[i]);
108 } catch (...) {
109 for (Size i=0; i<n; ++i)
110 if (quoteValues[i]!=Null<Real>())
111 quotes[i]->setValue(quoteValues[i]);
112 throw;
113 }
114
115 return result;
116 }
117
118 pair<Real, Real> bucketAnalysis(const Handle<SimpleQuote>& quote,
119 const vector<ext::shared_ptr<Instrument> >& instruments,
120 const vector<Real>& quantities,
121 Real shift,
123 Real referenceNpv) {
124 QL_REQUIRE(shift!=0.0, "zero shift not allowed");
125
126 pair<Real, Real> result(0.0, 0.0);
127 if (instruments.empty()) return result;
128
129 if (referenceNpv==Null<Real>())
130 referenceNpv = aggregateNPV(instruments, quantities);
131
132 if (!quote->isValid()) return result;
133 Real quoteValue = quote->value();
134
135 try {
136 quote->setValue(quoteValue+shift);
137 Real npv = aggregateNPV(instruments, quantities);
138 switch (type) {
139 case OneSide:
140 result.first = (npv-referenceNpv)/shift;
141 result.second = Null<Real>();
142 break;
143 case Centered:
144 {
145 quote->setValue(quoteValue-shift);
146 Real npv2 = aggregateNPV(instruments, quantities);
147 result.first = (npv-npv2)/(2.0*shift);
148 result.second = (npv-2.0*referenceNpv+npv2)/(shift*shift);
149 }
150 break;
151 default:
152 QL_FAIL("unknown SensitivityAnalysis (" <<
153 Integer(type) << ")");
154 }
155 quote->setValue(quoteValue);
156 } catch (...) {
157 quote->setValue(quoteValue);
158 throw;
159 }
160
161 return result;
162 }
163
164
165 void bucketAnalysis(vector<Real>& deltaVector, // delta result
166 vector<Real>& gammaVector, // gamma result
167 vector<Real>& refVals,
168 const Handle<SimpleQuote>& quote,
169 const vector<Handle<Quote> >& params,
170 Real shift,
171 SensitivityAnalysis type) {
172 QL_REQUIRE(shift!=0.0, "zero shift not allowed");
173
174 QL_REQUIRE(!params.empty(), "empty parameters vector");
175 Size m = params.size();
176 deltaVector.resize(m);
177 gammaVector.resize(m);
178
179 if (!quote->isValid()) {
180 for (Size j=0; j<m; ++j) {
181 deltaVector[j]=Null<Real>();
182 gammaVector[j]=Null<Real>();
183 }
184 return;
185 }
186 Real quoteValue = quote->value();
187
188 if (!refVals.empty()) {
189 QL_REQUIRE(refVals.size()==m,
190 "referenceValues has size " <<
191 refVals.size() << ", instead of " << m);
192 } else {
193 // calculate parameters' reference values
194 refVals = vector<Real>(m, Null<Real>());
195 for (Size j=0; j<m; ++j) {
196 if (params[j]->isValid()) // fault tolerant
197 refVals[j] = params[j]->value();
198 }
199 }
200
201 try {
202 switch (type) {
203 case OneSide:
204 {
205 quote->setValue(quoteValue+shift);
206 for (Size j=0; j<m; ++j) {
207 gammaVector[j] = Null<Real>();
208 if (refVals[j] != Null<Real>())
209 deltaVector[j] = (params[j]->value()-refVals[j])/shift;
210 else
211 deltaVector[j] = Null<Real>();
212 }
213 }
214 break;
215 case Centered:
216 {
217 quote->setValue(quoteValue+shift);
218 vector<Real> plus(m);
219 for (Size j=0; j<m; ++j) {
220 if (refVals[j] != Null<Real>())
221 plus[j] = params[j]->value();
222 }
223 quote->setValue(quoteValue-shift);
224 for (Size j=0; j<m; ++j) {
225 if (refVals[j] != Null<Real>()) {
226 Real minus = params[j]->value();
227 deltaVector[j] = (plus[j]-minus)/(2.0*shift);
228 gammaVector[j] = (plus[j]-2.0*refVals[j]+minus)/(shift*shift);
229 } else {
230 deltaVector[j] = Null<Real>();
231 gammaVector[j] = Null<Real>();
232 }
233 }
234 }
235 break;
236 default:
237 QL_FAIL("unknown SensitivityAnalysis (" <<
238 Integer(type) << ")");
239 } // end switch
240
241 // restore the quote to its original state
242 quote->setValue(quoteValue);
243
244 return;
245 } catch (...) {
246 // restore the quote to its original state
247 quote->setValue(quoteValue);
248 throw;
249 }
250
251 }
252
253
254
255
256
257 pair<vector<Real>, vector<Real> >
258 bucketAnalysis(const vector<Handle<SimpleQuote> >& quotes,
259 const vector<ext::shared_ptr<Instrument> >& instr,
260 const vector<Real>& quant,
261 Real shift,
263 {
264 QL_REQUIRE(!quotes.empty(), "empty SimpleQuote vector");
265 Size n = quotes.size();
266 pair<vector<Real>, vector<Real> > result(vector<Real>(n, 0.0),
267 vector<Real>(n, 0.0));
268
269 if (instr.empty()) return result;
270
271 Real npv = aggregateNPV(instr, quant);
272
273 pair<Real, Real> tmp;
274 for (Size i=0; i<n; ++i) {
275 tmp = bucketAnalysis(quotes[i], instr, quant, shift, type, npv);
276 result.first[i] = tmp.first;
277 result.second[i] = tmp.second;
278 }
279
280 return result;
281 }
282
283 void
284 bucketAnalysis(std::vector<std::vector<Real> >& deltaMatrix, // result
285 std::vector<std::vector<Real> >& gammaMatrix, // result
286 const vector<Handle<SimpleQuote> >& quotes,
287 const vector<Handle<Quote> >& parameters,
288 Real shift,
290 {
291 QL_REQUIRE(!quotes.empty(), "empty SimpleQuote vector");
292 QL_REQUIRE(!parameters.empty(), "empty parameters vector");
293
294 Size n = quotes.size();
295 deltaMatrix.resize(n);
296 gammaMatrix.resize(n);
297
298 Size m = parameters.size();
299 vector<Real> referenceValues(m, Null<Real>());
300 for (Size i=0; i<m; ++i) {
301 if (parameters[i]->isValid())
302 referenceValues[i] = parameters[i]->value();
303 }
304
305 for (Size i=0; i<n; ++i) {
306 bucketAnalysis(deltaMatrix[i], gammaMatrix[i], referenceValues,
307 quotes[i], parameters, shift, type);
308 }
309 }
310
311 pair<vector<vector<Real> >, vector<vector<Real> > >
312 bucketAnalysis(const vector<vector<Handle<SimpleQuote> > >& quotes,
313 const vector<ext::shared_ptr<Instrument> >& instr,
314 const vector<Real>& quant,
315 Real shift,
317 {
318 QL_REQUIRE(!quotes.empty(), "empty SimpleQuote range");
319 Size n = quotes.size();
320 vector<vector<Real> > first(n);
321 vector<vector<Real> > second(n);
322 for (Size i=0; i<n; ++i) {
323 Size tmp = quotes[i].size();
324 first[i] = vector<Real>(tmp, 0.0);
325 second[i] = vector<Real>(tmp, 0.0);
326 }
327
328 pair<vector<vector<Real> >, vector<vector<Real> > >
329 result(first, second);
330
331 if (instr.empty()) return result;
332
333 Real npv = aggregateNPV(instr, quant);
334
335 pair<Real, Real> tmp;
336 for (Size i=0; i<n; ++i) {
337 for (Size j=0; j<quotes[i].size(); ++j) {
338 tmp = bucketAnalysis(quotes[i][j], instr, quant, shift, type, npv);
339 result.first[i][j] = tmp.first;
340 result.second[i][j] = tmp.second;
341 }
342 }
343
344 return result;
345 }
346
347}
Shared handle to an observable.
Definition: handle.hpp:41
template class providing a null value for a given type.
Definition: null.hpp:76
QL_REAL Real
real number
Definition: types.hpp:50
QL_INTEGER Integer
integer number
Definition: types.hpp:35
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:35
Real aggregateNPV(const vector< ext::shared_ptr< Instrument > > &instruments, const vector< Real > &quant)
utility fuction for weighted sum of NPVs
pair< Real, Real > parallelAnalysis(const vector< Handle< SimpleQuote > > &quotes, const vector< ext::shared_ptr< Instrument > > &instruments, const vector< Real > &quantities, Real shift, SensitivityAnalysis type, Real referenceNpv)
parallel shift PV01 sensitivity analysis for a SimpleQuote vector
std::ostream & operator<<(std::ostream &out, GFunctionFactory::YieldCurveModel type)
pair< Real, Real > bucketAnalysis(const Handle< SimpleQuote > &quote, const vector< ext::shared_ptr< Instrument > > &instruments, const vector< Real > &quantities, Real shift, SensitivityAnalysis type, Real referenceNpv)
(bucket) PV01 sensitivity analysis for a (single) SimpleQuote
SensitivityAnalysis
Finite differences calculation.