Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
scenarioutilities.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2024 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
20
24#include <set>
25namespace ore {
26namespace analytics {
27
28Real getDifferenceScenario(const RiskFactorKey::KeyType keyType, const Real v1, const Real v2) {
29 switch (keyType) {
46 return v2 - v1;
47
57 return v2 / v1;
58
62 default:
63 QL_FAIL("getDifferenceScenario(): key type "
64 << keyType << " not expected, and not covered. This is an internal error, contact dev.");
65 };
66}
67
68Real addDifferenceToScenario(const RiskFactorKey::KeyType keyType, const Real v, const Real d) {
69 switch (keyType) {
86 return v + d;
87
97 return v * d;
98
102 default:
103 QL_FAIL("addDifferenceToScenario(): key type "
104 << keyType << " not expected, and not covered. This is an internal error, contact dev.");
105 };
106}
107
108QuantLib::ext::shared_ptr<Scenario> getDifferenceScenario(const QuantLib::ext::shared_ptr<Scenario>& s1,
109 const QuantLib::ext::shared_ptr<Scenario>& s2,
110 const Date& targetScenarioAsOf,
111 const Real targetScenarioNumeraire) {
112
113 QL_REQUIRE(s1->isAbsolute() && s2->isAbsolute(), "getDifferenceScenario(): both scenarios must be absolute ("
114 << std::boolalpha << s1->isAbsolute() << ", "
115 << s2->isAbsolute());
116
117 QL_REQUIRE(s1->keysHash() == s2->keysHash(),
118 "getDifferenceScenario(): both scenarios must have identical key sets");
119
120 Date asof = targetScenarioAsOf;
121 if (asof == Date() && s1->asof() == s2->asof())
122 asof = s1->asof();
123
124 QL_REQUIRE(asof != Date(), "getDifferenceScenario(): either both scenarios have to have the same asof date ("
125 << s1->asof() << ", " << s2->asof()
126 << ") or the target scenario asof date must be given.");
127
128 auto result = s1->clone();
129 result->setAsof(asof);
130 result->label("differenceScenario(" + s1->label() + "," + s2->label() + ")");
131 result->setNumeraire(targetScenarioNumeraire);
132 result->setAbsolute(false);
133
134 for (auto const& k : s1->keys()) {
135 result->add(k, getDifferenceScenario(k.keytype, s1->get(k), s2->get(k)));
136 }
137
138 return result;
139}
140
141QuantLib::ext::shared_ptr<Scenario> addDifferenceToScenario(const QuantLib::ext::shared_ptr<Scenario>& s,
142 const QuantLib::ext::shared_ptr<Scenario>& d,
143 const Date& targetScenarioAsOf,
144 const Real targetScenarioNumeraire) {
145
146 QL_REQUIRE(!d->isAbsolute(), "addDifferenceToScenario(): second argument must be difference scenario");
147 QL_REQUIRE(s->keysHash() == d->keysHash(),
148 "addDifferenceToScenario(): both scenarios must have identical key sets.");
149
150 Date asof = targetScenarioAsOf;
151 if (asof == Date() && s->asof() == d->asof())
152 asof = s->asof();
153
154 QL_REQUIRE(asof != Date(), "addDifferenceToScenario(): either both scenarios have to have the same asof date ("
155 << s->asof() << ", " << d->asof()
156 << ") or the target scenario asof date must be given.");
157
158 auto result = s->clone();
159 result->setAsof(asof);
160 result->label("sumScenario(" + s->label() + "," + d->label() + ")");
161 result->setNumeraire(targetScenarioNumeraire);
162 result->setAbsolute(s->isAbsolute());
163
164 for (auto const& k : s->keys()) {
165 result->add(k, addDifferenceToScenario(k.keytype, s->get(k), d->get(k)));
166 }
167
168 return result;
169}
170
171namespace {
172
173Size getKeyIndex(const std::vector<std::vector<Real>>& oldCoordinates, const std::vector<Size>& indices) {
174 Size resultIndex = 0;
175 Size multiplier = 1;
176 int workingIndex = indices.size() - 1;
177 do {
178 resultIndex += multiplier * indices[workingIndex];
179 multiplier *= oldCoordinates[workingIndex].size();
180 } while (--workingIndex >= 0);
181 return resultIndex;
182}
183
184double interpolatedValue(const std::vector<std::vector<Real>>& oldCoordinates,
185 const std::vector<std::vector<Real>>& newCoordinates, const std::vector<Size>& newIndex,
186 const std::pair<RiskFactorKey::KeyType, std::string>& key,
187 const QuantLib::ext::shared_ptr<Scenario>& scenario) {
188
189 Real w0, w1;
190 std::vector<Size> oldIndex0(oldCoordinates.size());
191 std::vector<Size> oldIndex1(oldCoordinates.size());
192
193 for (Size i = 0; i < oldCoordinates.size(); ++i) {
194 Size idx = std::distance(
195 oldCoordinates[i].begin(),
196 std::upper_bound(oldCoordinates[i].begin(), oldCoordinates[i].end(), newCoordinates[i][newIndex[i]]));
197 if (idx == 0) {
198 w0 = 1.0;
199 w1 = 0.0;
200 oldIndex0[i] = oldIndex1[i] = 0;
201 } else if (idx == oldCoordinates[i].size()) {
202 w0 = 0.0;
203 w1 = 1.0;
204 oldIndex0[i] = oldIndex1[i] = idx - 1;
205 } else {
206 oldIndex0[i] = idx - 1;
207 oldIndex1[i] = idx;
208 w1 = (newCoordinates[i][newIndex[i]] - oldCoordinates[i][idx - 1]) /
209 (oldCoordinates[i][idx] - oldCoordinates[i][idx - 1]);
210 w0 = 1.0 - w1;
211 }
212 }
213
214 Size keyIndex0 = getKeyIndex(oldCoordinates, oldIndex0);
215 Size keyIndex1 = getKeyIndex(oldCoordinates, oldIndex1);
216 try {
217 return w0 * scenario->get(RiskFactorKey(key.first, key.second, keyIndex0)) +
218 w1 * scenario->get(RiskFactorKey(key.first, key.second, keyIndex1));
219 } catch (const std::exception& e) {
220 QL_FAIL("recastScenario(): error while interpolating between "
221 << key.first << "/" << key.second << "/[" << keyIndex0 << "," << keyIndex1 << "]: " << e.what());
222 }
223}
224
225} // namespace
226
227QuantLib::ext::shared_ptr<Scenario> recastScenario(
228 const QuantLib::ext::shared_ptr<Scenario>& scenario,
229 const std::map<std::pair<RiskFactorKey::KeyType, std::string>, std::vector<std::vector<Real>>>& oldCoordinates,
230 const std::map<std::pair<RiskFactorKey::KeyType, std::string>, std::vector<std::vector<Real>>>& newCoordinates) {
231
232 auto result = QuantLib::ext::make_shared<SimpleScenario>(
233 scenario->asof(), scenario->label() + " (mapped to new coordinates)", scenario->getNumeraire());
234 result->setAbsolute(scenario->isAbsolute());
235
236 std::set<std::pair<RiskFactorKey::KeyType, std::string>> keys;
237 for (auto const& k : scenario->keys()) {
238 if(newCoordinates.count({k.keytype, k.name})==1){
239 keys.insert(std::make_pair(k.keytype, k.name));
240 TLOG("Insert keys " << k.keytype << " " << k.name)
241 } else{
242 TLOG("Recast skip " << k.keytype << " " << k.name);
243 }
244 }
245
246
247
248 for (auto const& k : keys) {
249
250 auto c0 = oldCoordinates.find(k);
251 auto c1 = newCoordinates.find(k);
252 QL_REQUIRE(c0 != scenario->coordinates().end(), "recastScenario(): no coordinates for "
253 << k.first << "/" << k.second
254 << " found in old coordinates. This is unexpected.");
255 QL_REQUIRE(c1 != scenario->coordinates().end(), "recastScenario(): no coordinates for "
256 << k.first << "/" << k.second
257 << " found in new coordinates. This is unexpected.");
258 QL_REQUIRE(c0->second.size() == c1->second.size(), "recastScenario(): number of dimensions in old ("
259 << c0->second.size() << ") and new ("
260 << c1->second.size() << ") coordinates for " << k.first
261 << "/" << k.second << " do not match.");
262 if (c1->second.size() == 0) {
263
264 // nothing to interpolate, just copy the single value associated to a rf key
265
266 RiskFactorKey key(k.first, k.second, 0);
267 result->add(key, scenario->get(key));
268
269 } else {
270 // interpolate new values from old values
271 Size newKeyIndex = 0;
272 std::vector<Size> indices(c0->second.size(), 0);
273 int workingIndex;
274 do {
275 workingIndex = indices.size() - 1;
276 while (workingIndex >= 0 && indices[workingIndex] == c1->second[workingIndex].size()) {
277 --workingIndex;
278 if (workingIndex >= 0)
279 indices[workingIndex] = 0;
280 }
281 if (workingIndex >= 0) {
282 RiskFactorKey key(k.first, k.second, newKeyIndex++);
283 auto iValue = interpolatedValue(c0->second, c1->second, indices, k, scenario);
284 TLOG("Add "<< key << " interpolated value = " << iValue);
285 result->add(key, iValue);
286 indices[workingIndex]++;
287 }
288 } while (workingIndex >= 0);
289 }
290 }
291 return result;
292}
293
294QuantLib::ext::shared_ptr<Scenario> recastScenario(
295 const QuantLib::ext::shared_ptr<Scenario>& scenario,
296 const std::map<std::pair<RiskFactorKey::KeyType, std::string>, std::vector<std::vector<Real>>>& oldCoordinates,
297 const std::set<std::tuple<RiskFactorKey::KeyType, std::string, std::vector<std::vector<Real>>>>& newCoordinates) {
298
299 std::map<std::pair<RiskFactorKey::KeyType, std::string>, std::vector<std::vector<Real>>> newCoordinatesMap;
300 for (const auto& [key, name, coordinates] : newCoordinates) {
301 newCoordinatesMap[{key, name}] = coordinates;
302 }
303 return recastScenario(scenario, oldCoordinates, newCoordinatesMap);
304}
305
306} // namespace analytics
307} // namespace ore
Data types stored in the scenario class.
Definition: scenario.hpp:48
KeyType
Risk Factor types.
Definition: scenario.hpp:51
#define TLOG(text)
Real getDifferenceScenario(const RiskFactorKey::KeyType keyType, const Real v1, const Real v2)
QuantLib::ext::shared_ptr< Scenario > recastScenario(const QuantLib::ext::shared_ptr< Scenario > &scenario, const std::map< std::pair< RiskFactorKey::KeyType, std::string >, std::vector< std::vector< Real > > > &oldCoordinates, const std::map< std::pair< RiskFactorKey::KeyType, std::string >, std::vector< std::vector< Real > > > &newCoordinates)
Real addDifferenceToScenario(const RiskFactorKey::KeyType keyType, const Real v, const Real d)
Size size(const ValueType &v)
Scenario class.
Scenario utility functions.
Simple scenario class.
Date asof(14, Jun, 2018)
string name