Skip to content

Commit 2221609

Browse files
mgronckijenkins
authored andcommitted
Merge branch 'QPR-12145' into QPR-12173
2 parents 52a6f6a + ef43d34 commit 2221609

48 files changed

Lines changed: 1138 additions & 1097 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Docker/Dockerfile-Test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ RUN apt-get update \
55
&& DEBIAN_FRONTEND=noninteractive apt-get install -y dos2unix python3 python3-pip libxml2-utils xsltproc \
66
&& apt-get clean \
77
&& rm -rf /var/lib/apt/lists/* \
8-
&& pip3 install matplotlib pandas nose nose_xunitmp datacompy jsondiff lxml
8+
&& pip3 install matplotlib pandas nose nose_xunitmp datacompy jsondiff lxml xmldiff
99

1010
CMD bash
1111

OREAnalytics/orea/app/analytics/parconversionanalytic.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,18 @@ void ParConversionAnalyticImpl::runAnalytic(const boost::shared_ptr<ore::data::I
8282

8383
auto& configs = analytic()->configurations();
8484

85-
auto simMarket = buildScenarioSimMarketForSensitivityAnalysis(
86-
analytic()->market(), configs.simMarketParams, configs.sensiScenarioData, configs.curveConfig,
87-
configs.todaysMarketParams, nullptr, inputs_->marketConfig("pricing"), true, false,
88-
*inputs_->iborFallbackConfig());
85+
auto simMarket = boost::make_shared<ScenarioSimMarket>(
86+
analytic()->market(), configs.simMarketParams, inputs_->marketConfig("pricing"),
87+
configs.curveConfig ? *configs.curveConfig : ore::data::CurveConfigurations(),
88+
configs.todaysMarketParams ? *configs.todaysMarketParams : ore::data::TodaysMarketParameters(), true,
89+
configs.sensiScenarioData->useSpreadedTermStructures(), false, false, *inputs_->iborFallbackConfig());
90+
91+
auto scenarioGenerator = boost::make_shared<SensitivityScenarioGenerator>(
92+
configs.sensiScenarioData, simMarket->baseScenario(), configs.simMarketParams, simMarket,
93+
boost::make_shared<DeltaScenarioFactory>(simMarket->baseScenario()), true, std::string(), true,
94+
simMarket->baseScenarioAbsolute());
95+
96+
simMarket->scenarioGenerator() = scenarioGenerator;
8997

9098
parAnalysis->computeParInstrumentSensitivities(simMarket);
9199

OREAnalytics/orea/cube/sensitivitycube.cpp

Lines changed: 65 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,16 @@ std::ostream& operator<<(std::ostream& out, const SensitivityCube::crossPair& cp
5757
SensitivityCube::SensitivityCube(const boost::shared_ptr<NPVSensiCube>& cube,
5858
const vector<ShiftScenarioDescription>& scenarioDescriptions,
5959
const map<RiskFactorKey, QuantLib::Real>& shiftsizes,
60-
const set<RiskFactorKey::KeyType>& twoSidedDeltas)
61-
: cube_(cube), scenarioDescriptions_(scenarioDescriptions), shiftSizes_(shiftsizes),
62-
twoSidedDeltas_(twoSidedDeltas) {
60+
const std::map<RiskFactorKey, ShiftScheme>& shiftSchemes)
61+
: cube_(cube), scenarioDescriptions_(scenarioDescriptions), shiftSizes_(shiftsizes), shiftSchemes_(shiftSchemes) {
6362
initialise();
6463
}
6564

6665
SensitivityCube::SensitivityCube(const boost::shared_ptr<NPVSensiCube>& cube,
6766
const vector<string>& scenarioDescriptions,
6867
const map<RiskFactorKey, QuantLib::Real>& shiftsizes,
69-
const set<RiskFactorKey::KeyType>& twoSidedDeltas)
70-
: cube_(cube), shiftSizes_(shiftsizes), twoSidedDeltas_(twoSidedDeltas) {
68+
const std::map<RiskFactorKey, ShiftScheme>& shiftSchemes)
69+
: cube_(cube), shiftSizes_(shiftsizes), shiftSchemes_(shiftSchemes) {
7170

7271
// Populate scenarioDescriptions_ from string descriptions
7372
scenarioDescriptions_.reserve(scenarioDescriptions.size());
@@ -79,6 +78,7 @@ SensitivityCube::SensitivityCube(const boost::shared_ptr<NPVSensiCube>& cube,
7978
}
8079

8180
void SensitivityCube::initialise() {
81+
8282
QL_REQUIRE(scenarioDescriptions_[0].type() == ShiftScenarioDescription::Type::Base,
8383
"Expected the first scenario in the sensitivity cube to be of type 'Base'");
8484

@@ -110,6 +110,7 @@ void SensitivityCube::initialise() {
110110
QL_REQUIRE(downFactors_.count(des.key1()) == 0, "Cannot have multiple down factors with "
111111
"the same risk factor key ["
112112
<< des.key1() << "]");
113+
factors_.insert(des.key1());
113114
downFactors_[des.key1()] = fd;
114115
downIndexToKey_[fd.index] = des.key1();
115116
break;
@@ -135,34 +136,26 @@ void SensitivityCube::initialise() {
135136
}
136137

137138
// Log warnings if each factor does not have a shift size entry and that it is not a Null<Real>()
138-
if (upFactors_.size() != shiftSizes_.size()) {
139-
WLOG("The number of 'Up' shifts (" << upFactors_.size() << ") does not equal "
140-
<< "the number of shift sizes (" << shiftSizes_.size() << ") supplied");
139+
if (factors_.size() != shiftSizes_.size()) {
140+
WLOG("The number of factors from up / down shifts (" << factors_.size() << ") does not equal "
141+
<< "the number of shift sizes (" << shiftSizes_.size()
142+
<< ") supplied");
141143
}
142144

143-
for (auto const& kv : upFactors_) {
144-
auto it = shiftSizes_.find(kv.first);
145+
for (auto const& f : factors_) {
146+
auto it = shiftSizes_.find(f);
145147
if (it == shiftSizes_.end()) {
146-
WLOG("No entry for risk factor " << kv.first << " in shift sizes.");
147-
}
148-
if (it->second == Null<Real>()) {
149-
WLOG("The shift size for risk factor " << kv.first << " is not valid.")
148+
WLOG("No entry for risk factor " << f << " in shift sizes.");
150149
}
151150
}
152151
}
153152

154153
bool SensitivityCube::hasTrade(const string& tradeId) const { return tradeIdx_.count(tradeId) > 0; }
155154

156-
RiskFactorKey SensitivityCube::upFactor(const Size upIndex) const {
157-
if (auto k = upIndexToKey_.find(upIndex); k != upIndexToKey_.end()) {
155+
RiskFactorKey SensitivityCube::upDownFactor(const Size index) const {
156+
if (auto k = upIndexToKey_.find(index); k != upIndexToKey_.end()) {
158157
return k->second;
159-
} else {
160-
return RiskFactorKey();
161-
}
162-
}
163-
164-
RiskFactorKey SensitivityCube::downFactor(const Size downIndex) const {
165-
if (auto k = downIndexToKey_.find(downIndex); k != downIndexToKey_.end()) {
158+
} else if (auto k = downIndexToKey_.find(index); k != downIndexToKey_.end()) {
166159
return k->second;
167160
} else {
168161
return RiskFactorKey();
@@ -178,7 +171,7 @@ SensitivityCube::crossPair SensitivityCube::crossFactor(const Size crossIndex) c
178171
}
179172

180173
bool SensitivityCube::hasScenario(const ShiftScenarioDescription& scenarioDescription) const {
181-
return scenarioIdx_.count(scenarioDescription) > 0;
174+
return scenarioIdx_.find(scenarioDescription) != scenarioIdx_.end();
182175
}
183176

184177
std::string SensitivityCube::factorDescription(const RiskFactorKey& riskFactorKey) const {
@@ -199,6 +192,12 @@ Real SensitivityCube::shiftSize(const RiskFactorKey& riskFactorKey) const {
199192
return it->second;
200193
}
201194

195+
ShiftScheme SensitivityCube::shiftScheme(const RiskFactorKey& riskFactorKey) const {
196+
auto it = shiftSchemes_.find(riskFactorKey);
197+
QL_REQUIRE(it != shiftSchemes_.end(), "Risk factor, " << riskFactorKey << ", was not found in the shift schemes.");
198+
return it->second;
199+
}
200+
202201
Real SensitivityCube::npv(const string& tradeId) const { return cube_->getT0(tradeId, 0); }
203202

204203
Real SensitivityCube::npv(Size id) const { return cube_->getT0(id, 0); }
@@ -211,77 +210,76 @@ Real SensitivityCube::npv(const string& tradeId, const ShiftScenarioDescription&
211210
return npv(tradeIdx, scenarioIdx);
212211
}
213212

214-
Real SensitivityCube::delta(Size id, Size scenarioIdx) const {
215-
return cube_->get(id, scenarioIdx) - cube_->getT0(id, 0);
216-
}
217-
218-
Real SensitivityCube::delta(Size id, Size upIdx, Size downIdx) const {
219-
return (cube_->get(id, upIdx) - cube_->get(id, downIdx)) / 2.0;
220-
}
221-
222-
Real SensitivityCube::delta(const string& tradeId, const RiskFactorKey& riskFactorKey) const {
223-
Size scenarioIdx = index(riskFactorKey, upFactors_).index;
224-
Size tradeIdx = cube_->getTradeIndex(tradeId);
225-
if (!twoSidedDelta(riskFactorKey.keytype)) {
226-
return delta(tradeIdx, scenarioIdx);
227-
} else {
213+
Real SensitivityCube::delta(const Size tradeIdx, const RiskFactorKey& riskFactorKey) const {
214+
auto s = shiftSchemes_.find(riskFactorKey);
215+
QL_REQUIRE(s != shiftSchemes_.end(),
216+
"SensitivityCube::delta(" << tradeIdx << ", " << riskFactorKey << "): no shift scheme stored.");
217+
if (s->second == ShiftScheme::Forward) {
218+
Size scenarioIdx = index(riskFactorKey, upFactors_).index;
219+
return cube_->get(tradeIdx, scenarioIdx) - cube_->getT0(tradeIdx, 0);
220+
} else if (s->second == ShiftScheme::Backward) {
221+
Size scenarioIdx = index(riskFactorKey, downFactors_).index;
222+
return cube_->getT0(tradeIdx, 0) - cube_->get(tradeIdx, scenarioIdx);
223+
} else if (s->second == ShiftScheme::Central) {
224+
Size upIdx = index(riskFactorKey, upFactors_).index;
228225
Size downIdx = index(riskFactorKey, downFactors_).index;
229-
return delta(tradeIdx, scenarioIdx, downIdx);
226+
return (cube_->get(tradeIdx, upIdx) - cube_->get(tradeIdx, downIdx)) / 2.0;
227+
} else {
228+
QL_FAIL("SensitivityCube::delta(" << tradeIdx << ", " << riskFactorKey << "): unknown shift scheme '"
229+
<< s->second << "'");
230230
}
231231
}
232232

233-
Real SensitivityCube::gamma(Size id, Size upScenarioIdx, Size downScenarioIdx) const {
234-
235-
Real baseNpv = cube_->getT0(id, 0);
236-
Real upNpv = cube_->get(id, upScenarioIdx);
237-
Real downNpv = cube_->get(id, downScenarioIdx);
238-
239-
return upNpv - 2.0 * baseNpv + downNpv;
233+
Real SensitivityCube::delta(const string& tradeId, const RiskFactorKey& riskFactorKey) const {
234+
return delta(cube_->getTradeIndex(tradeId), riskFactorKey);
240235
}
241236

242-
Real SensitivityCube::gamma(const std::string& tradeId, const RiskFactorKey& riskFactorKey) const {
237+
Real SensitivityCube::gamma(const Size tradeIdx, const RiskFactorKey& riskFactorKey) const {
243238
Size upIdx = index(riskFactorKey, upFactors_).index;
244239
Size downIdx = index(riskFactorKey, downFactors_).index;
245-
Size tradeIdx = cube_->getTradeIndex(tradeId);
240+
Real baseNpv = cube_->getT0(tradeIdx, 0);
241+
Real upNpv = cube_->get(tradeIdx, upIdx);
242+
Real downNpv = cube_->get(tradeIdx, downIdx);
243+
return upNpv - 2.0 * baseNpv + downNpv;
244+
}
246245

247-
return gamma(tradeIdx, upIdx, downIdx);
246+
Real SensitivityCube::gamma(const string& tradeId, const RiskFactorKey& riskFactorKey) const {
247+
return gamma(cube_->getTradeIndex(tradeId), riskFactorKey);
248248
}
249249

250-
Real SensitivityCube::crossGamma(Size id, Size upIdx_1, Size upIdx_2, Size crossIdx) const {
250+
QuantLib::Real SensitivityCube::crossGamma(QuantLib::Size id, QuantLib::Size upIdx_1, QuantLib::Size upIdx_2,
251+
QuantLib::Size crossIdx) const {
251252
// Approximate f_{xy}|(x,y) by
252253
// ([f_{x}|(x,y + dy)] - [f_{x}|(x,y)]) / dy
253254
// ([f(x + dx,y + dy) - f(x, y + dy)] - [f(x + dx,y) - f(x,y)]) / (dx dy)
254255
Real baseNpv = cube_->getT0(id, 0);
255256
Real upNpv_1 = cube_->get(id, upIdx_1);
256257
Real upNpv_2 = cube_->get(id, upIdx_2);
257258
Real crossNpv = cube_->get(id, crossIdx);
258-
259259
return crossNpv - upNpv_1 - upNpv_2 + baseNpv;
260260
}
261261

262-
std::set<RiskFactorKey> SensitivityCube::relevantRiskFactors() {
263-
std::set<RiskFactorKey> result;
264-
for (auto const i : cube_->relevantScenarios()) {
265-
result.insert(scenarioDescriptions_[i].key1());
266-
if (scenarioDescriptions_[i].type() == ShiftScenarioDescription::Type::Cross)
267-
result.insert(scenarioDescriptions_[i].key2());
268-
}
269-
return result;
270-
}
271-
272-
Real SensitivityCube::crossGamma(const string& tradeId, const crossPair& riskFactorKeyPair) const {
262+
Real SensitivityCube::crossGamma(const Size tradeIdx, const crossPair& riskFactorKeyPair) const {
273263
FactorData upFd_1, upFd_2;
274-
Size upIdx_1, upIdx_2, crossIdx, tradeIdx;
264+
Size upIdx_1, upIdx_2, crossIdx;
275265
std::tie(upFd_1, upFd_2, crossIdx) = index(riskFactorKeyPair, crossFactors_);
276266
upIdx_1 = upFd_1.index;
277267
upIdx_2 = upFd_2.index;
278-
tradeIdx = cube_->getTradeIndex(tradeId);
279-
280268
return crossGamma(tradeIdx, upIdx_1, upIdx_2, crossIdx);
281269
}
282270

283-
bool SensitivityCube::twoSidedDelta(const RiskFactorKey::KeyType& keyType) const {
284-
return twoSidedDeltas_.count(keyType) == 1;
271+
Real SensitivityCube::crossGamma(const std::string& tradeId, const crossPair& riskFactorKeyPair) const {
272+
return crossGamma(cube_->getTradeIndex(tradeId), riskFactorKeyPair);
273+
}
274+
275+
std::set<RiskFactorKey> SensitivityCube::relevantRiskFactors() const {
276+
std::set<RiskFactorKey> result;
277+
for (auto const i : cube_->relevantScenarios()) {
278+
result.insert(scenarioDescriptions_[i].key1());
279+
if (scenarioDescriptions_[i].type() == ShiftScenarioDescription::Type::Cross)
280+
result.insert(scenarioDescriptions_[i].key2());
281+
}
282+
return result;
285283
}
286284

287285
} // namespace analytics

0 commit comments

Comments
 (0)