Skip to content

Commit df88f02

Browse files
pcaspersjenkins
authored andcommitted
QPR-11641 fix upDownFactor(), add crossFactor() method
upDownFactor() only worked for up factors so far (which was good enough for our use cases)
1 parent 9e8ff82 commit df88f02

2 files changed

Lines changed: 47 additions & 37 deletions

File tree

OREAnalytics/orea/cube/sensitivitycube.cpp

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@ using namespace std;
2626

2727
using std::make_pair;
2828

29-
// Ease the notation below
30-
using bm_type = boost::bimap<ore::analytics::RiskFactorKey, ore::analytics::SensitivityCube::FactorData>;
31-
typedef bm_type::left_map left_map_type;
29+
namespace ore {
30+
namespace analytics {
3231

3332
namespace {
3433

@@ -40,7 +39,9 @@ template <class KeyType, class ValueType> ValueType index(const KeyType& k, cons
4039
return it->second;
4140
}
4241

43-
ore::analytics::SensitivityCube::FactorData index(const ore::analytics::RiskFactorKey& k, const left_map_type& m) {
42+
ore::analytics::SensitivityCube::FactorData
43+
index(const ore::analytics::RiskFactorKey& k,
44+
const std::map<ore::analytics::RiskFactorKey, SensitivityCube::FactorData>& m) {
4445

4546
auto it = m.find(k);
4647
QL_REQUIRE(it != m.end(), "Key, " << k << ", was not found in the sensitivity cube.");
@@ -49,11 +50,6 @@ ore::analytics::SensitivityCube::FactorData index(const ore::analytics::RiskFact
4950

5051
} // namespace
5152

52-
namespace ore {
53-
namespace analytics {
54-
55-
typedef SensitivityCube::crossPair crossPair;
56-
5753
std::ostream& operator<<(std::ostream& out, const SensitivityCube::crossPair& cp) {
5854
return out << cp.first << "-" << cp.second;
5955
}
@@ -103,24 +99,27 @@ void SensitivityCube::initialise() {
10399
// Populate factors_ = list of factors for which we can calculate a delta/gamma
104100
switch (des.type()) {
105101
case ShiftScenarioDescription::Type::Up:
106-
QL_REQUIRE(upFactors_.left.count(des.key1()) == 0, "Cannot have multiple up factors with "
107-
"the same risk factor key["
108-
<< des.key1() << "]");
102+
QL_REQUIRE(upFactors_.count(des.key1()) == 0, "Cannot have multiple up factors with "
103+
"the same risk factor key["
104+
<< des.key1() << "]");
109105
factors_.insert(des.key1());
110-
upFactors_.insert(bm_type::value_type(des.key1(), fd));
106+
upFactors_[des.key1()] = fd;
107+
upDownIndexToKey_[fd.index] = des.key1();
111108
break;
112109
case ShiftScenarioDescription::Type::Down:
113110
QL_REQUIRE(downFactors_.count(des.key1()) == 0, "Cannot have multiple down factors with "
114111
"the same risk factor key ["
115112
<< des.key1() << "]");
116113
downFactors_[des.key1()] = fd;
114+
upDownIndexToKey_[fd.index] = des.key1();
117115
break;
118116
case ShiftScenarioDescription::Type::Cross:
119117
factorPair = make_pair(des.key1(), des.key2());
120118
QL_REQUIRE(crossFactors.count(factorPair) == 0, "Cannot have multiple cross factors with "
121119
"the same risk factor key pair ["
122120
<< des.key1() << ", " << des.key2() << "]");
123121
crossFactors[factorPair] = i;
122+
crossIndexToKey_[i] = factorPair;
124123
break;
125124
default:
126125
// Do nothing
@@ -130,8 +129,8 @@ void SensitivityCube::initialise() {
130129

131130
// Add each cross factor to crossFactors with index of the two contributing factors
132131
for (auto cf : crossFactors) {
133-
FactorData id_1 = index(cf.first.first, upFactors_.left);
134-
FactorData id_2 = index(cf.first.second, upFactors_.left);
132+
FactorData id_1 = index(cf.first.first, upFactors_);
133+
FactorData id_2 = index(cf.first.second, upFactors_);
135134
crossFactors_[cf.first] = make_tuple(id_1, id_2, cf.second);
136135
}
137136

@@ -141,7 +140,7 @@ void SensitivityCube::initialise() {
141140
<< "the number of shift sizes (" << shiftSizes_.size() << ") supplied");
142141
}
143142

144-
for (auto const& kv : upFactors_.left) {
143+
for (auto const& kv : upFactors_) {
145144
auto it = shiftSizes_.find(kv.first);
146145
if (it == shiftSizes_.end()) {
147146
WLOG("No entry for risk factor " << kv.first << " in shift sizes.");
@@ -155,27 +154,33 @@ void SensitivityCube::initialise() {
155154
bool SensitivityCube::hasTrade(const string& tradeId) const { return tradeIdx_.count(tradeId) > 0; }
156155

157156
RiskFactorKey SensitivityCube::upDownFactor(const Size upDownIndex) const {
158-
FactorData fd;
159-
fd.index = upDownIndex;
160-
auto it = upFactors_.right.find(fd);
161-
if (it == upFactors_.right.end())
157+
if (auto k = upDownIndexToKey_.find(upDownIndex); k != upDownIndexToKey_.end()) {
158+
return k->second;
159+
} else {
162160
return RiskFactorKey();
163-
else
164-
return it->second;
161+
}
162+
}
163+
164+
SensitivityCube::crossPair SensitivityCube::crossFactor(const Size crossIndex) const {
165+
if (auto k = crossIndexToKey_.find(crossIndex); k != crossIndexToKey_.end()) {
166+
return k->second;
167+
} else {
168+
return std::make_pair(RiskFactorKey(), RiskFactorKey());
169+
}
165170
}
166171

167172
bool SensitivityCube::hasScenario(const ShiftScenarioDescription& scenarioDescription) const {
168173
return scenarioIdx_.count(scenarioDescription) > 0;
169174
}
170175

171176
std::string SensitivityCube::factorDescription(const RiskFactorKey& riskFactorKey) const {
172-
Size scenarioIdx = index(riskFactorKey, upFactors_.left).index;
177+
Size scenarioIdx = index(riskFactorKey, upFactors_).index;
173178
return scenarioDescriptions_[scenarioIdx].factor1();
174179
}
175180

176181
const set<RiskFactorKey>& SensitivityCube::factors() const { return factors_; }
177182

178-
const std::map<crossPair, tuple<SensitivityCube::FactorData, SensitivityCube::FactorData, Size>>&
183+
const std::map<SensitivityCube::crossPair, tuple<SensitivityCube::FactorData, SensitivityCube::FactorData, Size>>&
179184
SensitivityCube::crossFactors() const {
180185
return crossFactors_;
181186
}
@@ -207,7 +212,7 @@ Real SensitivityCube::delta(Size id, Size upIdx, Size downIdx) const {
207212
}
208213

209214
Real SensitivityCube::delta(const string& tradeId, const RiskFactorKey& riskFactorKey) const {
210-
Size scenarioIdx = index(riskFactorKey, upFactors_.left).index;
215+
Size scenarioIdx = index(riskFactorKey, upFactors_).index;
211216
Size tradeIdx = cube_->getTradeIndex(tradeId);
212217
if (!twoSidedDelta(riskFactorKey.keytype)) {
213218
return delta(tradeIdx, scenarioIdx);
@@ -227,7 +232,7 @@ Real SensitivityCube::gamma(Size id, Size upScenarioIdx, Size downScenarioIdx) c
227232
}
228233

229234
Real SensitivityCube::gamma(const std::string& tradeId, const RiskFactorKey& riskFactorKey) const {
230-
Size upIdx = index(riskFactorKey, upFactors_.left).index;
235+
Size upIdx = index(riskFactorKey, upFactors_).index;
231236
Size downIdx = index(riskFactorKey, downFactors_).index;
232237
Size tradeIdx = cube_->getTradeIndex(tradeId);
233238

OREAnalytics/orea/cube/sensitivitycube.hpp

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ class SensitivityCube {
8080
is not an up/down scenario (to be reviewed) */
8181
RiskFactorKey upDownFactor(const Size upDownIndex) const;
8282

83+
/*! Return factor for given cross scenario index or None if given index
84+
is not a cross scenario (to be reviewed) */
85+
crossPair crossFactor(const Size crossIndex) const;
86+
8387
//! Check if the cube has scenario NPVs for scenario with description \p scenarioDescription
8488
bool hasScenario(const ShiftScenarioDescription& scenarioDescription) const;
8589

@@ -90,10 +94,10 @@ class SensitivityCube {
9094
//! Returns the set of risk factor keys for which a delta and gamma can be calculated
9195
const std::set<RiskFactorKey>& factors() const;
9296

93-
//! Return the map of up risk factors to it's factor data
94-
const boost::bimap<RiskFactorKey, SensitivityCube::FactorData>& upFactors() const { return upFactors_; };
97+
//! Return the map of up risk factors to its factor data
98+
const std::map<RiskFactorKey, SensitivityCube::FactorData>& upFactors() const { return upFactors_; };
9599

96-
//! Return the map of down risk factors to it's factor data
100+
//! Return the map of down risk factors to its factor data
97101
const std::map<RiskFactorKey, SensitivityCube::FactorData>& downFactors() const { return downFactors_; };
98102

99103
//! Returns the set of pairs of risk factor keys for which a cross gamma is available
@@ -161,23 +165,24 @@ class SensitivityCube {
161165
std::map<std::string, QuantLib::Size> tradeIdx_;
162166
std::map<ShiftScenarioDescription, QuantLib::Size> scenarioIdx_;
163167

164-
// Suppress warnings from Boost concept_check.hpp (VS 16.9.0, Boost 1.72.0).
165-
// warning C4834: discarding return value of function with 'nodiscard' attribute
166-
#pragma warning( push )
167-
#pragma warning( disable : 4834 )
168-
boost::bimap<RiskFactorKey, FactorData> upFactors_;
169-
#pragma warning( pop )
170-
171-
std::map<RiskFactorKey, FactorData> downFactors_;
168+
std::map<RiskFactorKey, FactorData> upFactors_, downFactors_;
172169
// map of crossPair to tuple of (data of first \p RiskFactorKey, data of second \p RiskFactorKey, index of
173170
// crossFactor)
174171
std::map<crossPair, std::tuple<FactorData, FactorData, QuantLib::Size>> crossFactors_;
175172

176173
// Set of risk factor key types where we want a two-sided delta calculation.
177174
std::set<RiskFactorKey::KeyType> twoSidedDeltas_;
175+
176+
// map of up / down factor index to risk factor key
177+
std::map<QuantLib::Size, RiskFactorKey> upDownIndexToKey_;
178+
179+
// map of cross factor index to risk factor pair
180+
std::map<QuantLib::Size, crossPair> crossIndexToKey_;
181+
178182
};
179183

180184
std::ostream& operator<<(std::ostream& out, const SensitivityCube::crossPair& cp);
181185

182186
} // namespace analytics
183187
} // namespace ore
188+
#

0 commit comments

Comments
 (0)