Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
sensitivityaggregator.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2017 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
22#include <ql/errors.hpp>
23
25using std::function;
26using std::map;
27using std::set;
28using std::string;
29
30namespace ore {
31namespace analytics {
32
33SensitivityAggregator::SensitivityAggregator(const map<string, set<pair<string, Size>>>& categories)
34 : setCategories_(categories) {
35
36 // Initialise the category functions
37 for (const auto& kv : setCategories_) {
38 categories_[kv.first] = bind(&SensitivityAggregator::inCategory, this, std::placeholders::_1, kv.first);
39 }
40
41 // Initialise the categorised records
42 init();
43}
44
45SensitivityAggregator::SensitivityAggregator(const map<string, function<bool(string)>>& categories)
46 : categories_(categories) {
47
48 // Initialise the categorised records
49 init();
50}
51
52void SensitivityAggregator::aggregate(SensitivityStream& ss, const QuantLib::ext::shared_ptr<ScenarioFilter>& filter) {
53 // Ensure at start of stream
54 ss.reset();
55
56 // Loop over stream's records
57 while (SensitivityRecord sr = ss.next()) {
58 // Skip this record if the risk factor is not in the filter
59 if (!sr.isCrossGamma() && !filter->allow(sr.key_1))
60 continue;
61 if (sr.isCrossGamma() && (!filter->allow(sr.key_1) || !filter->allow(sr.key_2)))
62 continue;
63
64 // "Blank out" trade ID before adding
65 string tradeId = sr.tradeId;
66 sr.tradeId = "";
67
68 // Update aggRecords_ for each category
69 for (const auto& kv : categories_) {
70 // Check if the sensitivity record's trade ID is in the category
71 if (kv.second(tradeId)) {
72 DLOG("Updating aggregated sensitivities for category " << kv.first << " with record: " << sr);
73 add(sr, aggRecords_[kv.first]);
74 }
75 }
76 }
77}
78
79void SensitivityAggregator::reset() {
80 // Clear the aggregated sensitivities
81 aggRecords_.clear();
82
83 // Initialise the categorised records
84 init();
85}
86
87const set<SensitivityRecord>& SensitivityAggregator::sensitivities(const string& category) const {
88
89 auto it = aggRecords_.find(category);
90 QL_REQUIRE(it != aggRecords_.end(),
91 "The category " << category << " was not used in the construction of the SensitivityAggregator");
92
93 return it->second;
94}
95
96void SensitivityAggregator::generateDeltaGamma(const string& category, map<RiskFactorKey, Real>& deltas,
97 map<CrossPair, Real>& gammas) {
98
99 auto srs = sensitivities(category);
100 for (const auto& sr : srs) {
101 if (!sr.isCrossGamma()) {
102 QL_REQUIRE(deltas.count(sr.key_1) == 0,
103 "Duplicate sensitivity entry for risk factor key " << sr.key_1 << " in the set");
104 deltas[sr.key_1] = sr.delta;
105 gammas[std::make_pair(sr.key_1, sr.key_1)] = sr.gamma;
106 } else {
107 auto keyPair =
108 sr.key_1 < sr.key_2 ? std::make_pair(sr.key_1, sr.key_2) : std::make_pair(sr.key_2, sr.key_1);
109 QL_REQUIRE(gammas.count(keyPair) == 0, "Duplicate sensitivity entry for cross gamma pair ["
110 << keyPair.first << ", " << keyPair.second << "] in the set");
111 gammas[keyPair] = sr.gamma;
112 }
113 }
114
115 // Final check that all cross gamma keys are in delta keys
116 for (const auto& kv : gammas) {
117 QL_REQUIRE(deltas.count(kv.first.first) > 0,
118 "The key " << kv.first.first << " is in the cross gammas but not in the deltas");
119 QL_REQUIRE(deltas.count(kv.first.second) > 0,
120 "The key " << kv.first.second << " is in the cross gammas but not in the deltas");
121 }
122}
123
124void SensitivityAggregator::init() {
125 // Add an empty set for each of the categories
126 for (const auto& kv : categories_) {
127 aggRecords_[kv.first] = {};
128 }
129}
130
131void SensitivityAggregator::add(SensitivityRecord& sr, set<SensitivityRecord>& records) {
132 // Try to insert sr. This will only pass if sr is not there already.
133 auto p = records.insert(sr);
134 if (!p.second) {
135 // If sr is already in the set, update it.
136 p.first->baseNpv += sr.baseNpv;
137 p.first->delta += sr.delta;
138 p.first->gamma += sr.gamma;
139 }
140}
141
142bool SensitivityAggregator::inCategory(const string& tradeId, const string& category) const {
143 QL_REQUIRE(setCategories_.count(category), "The category " << category << " is not valid");
144 auto tradeIds = setCategories_.at(category);
145 for (auto it = tradeIds.begin(); it != tradeIds.end(); ++it) {
146 if (it->first == tradeId)
147 return true;
148 }
149 return false;
150}
151
152} // namespace analytics
153} // namespace ore
A scenario filter can exclude certain key from updating the scenario.
SensitivityAggregator(const std::map< std::string, std::set< std::pair< std::string, QuantLib::Size > > > &categories)
Base Class for streaming SensitivityRecords.
virtual void reset()=0
Resets the stream so that SensitivityRecord objects can be streamed again.
virtual SensitivityRecord next()=0
Returns the next SensitivityRecord in the stream.
SafeStack< Filter > filter
#define DLOG(text)
Class for aggregating SensitivityRecords.