Skip to content

Commit 1659a3c

Browse files
committed
Merge branch 'feature/QPR-13711' into 'master'
QPR-13711 PNL/PNL Explain issues Closes QPR-13711 See merge request qs/oreplus!3109
2 parents 8e8a1fc + da982d1 commit 1659a3c

13 files changed

Lines changed: 84 additions & 30 deletions

ORE-SWIG/OREAnalytics-SWIG/SWIG/orea_app.i

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ public:
128128
void setBuildFailedTrades(bool b);
129129
void setObservationModel(const std::string& s);
130130
void setImplyTodaysFixings(bool b);
131+
void setFixingCutOffDate(Date d);
131132
void setUseAtParCouponsCurves(bool b);
132133
void setUseAtParCouponsTrades(bool b);
133134
void setMarketConfig(const std::string& config, const std::string& context);
@@ -142,6 +143,9 @@ public:
142143
void setConventions(const std::string& xml);
143144
void setConventionsFromFile(const std::string& fileName);
144145
void setConventions(const ext::shared_ptr<Conventions>& convs);
146+
void setMporConventions(const std::string& xml);
147+
void setMporConventionsFromFile(const std::string& fileName);
148+
void setIborFallbackConfig(const std::string& xml);
145149
void setIborFallbackConfig(const std::string& xml);
146150
void setIborFallbackConfigFromFile(const std::string& fileName);
147151
void setCurveConfigs(const std::string& xml, std::string id = std::string());

OREAnalytics/orea/app/analytics/pnlexplainanalytic.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ void PnlExplainAnalyticImpl::runAnalytic(const QuantLib::ext::shared_ptr<ore::da
135135
t0SimMarket->scenarioGenerator() = sgen;
136136

137137
// use difference scenarios for par sensi pnl explain
138-
zeroScenarios->setGenerateDifferenceScenarios(t0SimMarket->useSpreadedTermStructures());
138+
zeroScenarios->setGenerateDifferenceScenarios(true);
139139

140140
QL_REQUIRE(parSensiAnalysis, "Par Sensi Analysis required");
141141
auto parScenarios = QuantLib::ext::make_shared<ZeroToParScenarioGenerator>(zeroScenarios, t0SimMarket,

OREAnalytics/orea/app/inputparameters.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,18 @@ void InputParameters::setConventionsFromFile(const std::string& fileName) {
169169
InstrumentConventions::instance().setConventions(conventions_);
170170
}
171171

172+
void InputParameters::setMporConventions(const std::string& xml) {
173+
mporConventions_ = QuantLib::ext::make_shared<Conventions>();
174+
mporConventions_->fromXMLString(xml);
175+
InstrumentConventions::instance().setConventions(mporConventions_, mporDate());
176+
}
177+
178+
void InputParameters::setMporConventionsFromFile(const std::string& fileName) {
179+
mporConventions_ = QuantLib::ext::make_shared<Conventions>();
180+
mporConventions_->fromFile(fileName);
181+
InstrumentConventions::instance().setConventions(mporConventions_, mporDate());
182+
}
183+
172184
void InputParameters::setCurveConfigs(const std::string& xml, std::string id) {
173185
auto curveConfig = QuantLib::ext::make_shared<CurveConfigurations>();
174186
curveConfig->fromXMLString(xml);

OREAnalytics/orea/app/inputparameters.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ class InputParameters {
134134
void setBuildFailedTrades(bool b) { buildFailedTrades_ = b; }
135135
void setObservationModel(const std::string& s) { observationModel_ = s; }
136136
void setImplyTodaysFixings(bool b) { implyTodaysFixings_ = b; }
137+
void setFixingCutOffDate(Date d) { fixingCutOffDate_ = d; }
137138
void setUseAtParCouponsCurves(bool b) { useAtParCouponsCurves_ = b; }
138139
void setUseAtParCouponsTrades(bool b) { useAtParCouponsTrades_ = b; }
139140
void setEnrichIndexFixings(bool b) { enrichIndexFixings_ = b; }
@@ -153,6 +154,8 @@ class InputParameters {
153154
void setConventions(const std::string& xml);
154155
void setConventions(const QuantLib::ext::shared_ptr<Conventions>& convs);
155156
void setConventionsFromFile(const std::string& fileName);
157+
void setMporConventions(const std::string& xml);
158+
void setMporConventionsFromFile(const std::string& fileName);
156159
void setIborFallbackConfig(const std::string& xml);
157160
void setIborFallbackConfigFromFile(const std::string& fileName);
158161
void setBaselTrafficLightConfig(const std::string& xml);
@@ -613,6 +616,7 @@ class InputParameters {
613616
bool buildFailedTrades() const { return buildFailedTrades_; }
614617
const std::string& observationModel() const { return observationModel_; }
615618
bool implyTodaysFixings() const { return implyTodaysFixings_; }
619+
Date fixingCutOffDate() const { return fixingCutOffDate_; }
616620
bool useAtParCouponsCurves() const { return useAtParCouponsCurves_; }
617621
bool useAtParCouponsTrades() const { return useAtParCouponsTrades_; }
618622
bool enrichIndexFixings() const { return enrichIndexFixings_; }
@@ -622,6 +626,7 @@ class InputParameters {
622626
const std::string& marketConfig(const std::string& context);
623627
const QuantLib::ext::shared_ptr<ore::data::BasicReferenceDataManager>& refDataManager() const { return refDataManager_; }
624628
const QuantLib::ext::shared_ptr<ore::data::Conventions>& conventions() const { return conventions_; }
629+
const QuantLib::ext::shared_ptr<ore::data::Conventions>& mporConventions() const { return mporConventions_; }
625630
const QuantLib::ext::shared_ptr<ore::data::IborFallbackConfig>& iborFallbackConfig() const { return iborFallbackConfig_; }
626631
const QuantLib::ext::shared_ptr<ore::data::BaselTrafficLightData>& baselTrafficLightConfig() const { return baselTrafficLightConfig_; }
627632

@@ -1106,6 +1111,7 @@ class InputParameters {
11061111
bool buildFailedTrades_ = true;
11071112
std::string observationModel_ = "None";
11081113
bool implyTodaysFixings_ = false;
1114+
Date fixingCutOffDate_;
11091115
bool useAtParCouponsCurves_ = true;
11101116
bool useAtParCouponsTrades_ = true;
11111117
bool enrichIndexFixings_ = false;
@@ -1119,7 +1125,7 @@ class InputParameters {
11191125
std::map<std::string, std::string> marketConfigs_;
11201126
QuantLib::ext::shared_ptr<ore::data::BasicReferenceDataManager> refDataManager_;
11211127
QuantLib::ext::shared_ptr<ore::data::BaselTrafficLightData> baselTrafficLightConfig_;
1122-
QuantLib::ext::shared_ptr<ore::data::Conventions> conventions_;
1128+
QuantLib::ext::shared_ptr<ore::data::Conventions> conventions_, mporConventions_;
11231129
QuantLib::ext::shared_ptr<ore::data::IborFallbackConfig> iborFallbackConfig_;
11241130
CurveConfigurationsManager curveConfigs_;
11251131
QuantLib::ext::shared_ptr<ore::data::CalendarAdjustmentConfig> calendarAdjustment_;

OREAnalytics/orea/app/marketdatainmemoryloader.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ void MarketDataInMemoryLoaderImpl::retrieveMarketData(
3636
const Date& relabelDate) {
3737

3838
if (inputs_->entireMarket()) {
39-
loadDataFromBuffers(*loader, marketData_, std::vector<std::string>(), inputs_->implyTodaysFixings());
39+
loadDataFromBuffers(*loader, marketData_, std::vector<std::string>(), inputs_->implyTodaysFixings(), inputs_->fixingCutOffDate());
4040
} else {
4141
QL_FAIL("MarketDataInMemoryLoaderImpl::retrieveMarketData() requires inputs_->entireMarket()");
4242
}
@@ -47,7 +47,8 @@ void MarketDataInMemoryLoaderImpl::retrieveFixings(const QuantLib::ext::shared_p
4747
map<pair<string, Date>, set<Date>> lastAvailableFixingLookupMap) {
4848

4949
if (inputs_->allFixings()) {
50-
loadDataFromBuffers(*loader, std::vector<std::string>(), fixingData_, inputs_->implyTodaysFixings());
50+
loadDataFromBuffers(*loader, std::vector<std::string>(), fixingData_, inputs_->implyTodaysFixings(),
51+
inputs_->fixingCutOffDate());
5152
} else {
5253
QL_FAIL("MarketDataInMemoryLoaderImpl::retrieveFixings() requires inputs_->allFixings()");
5354
}

OREAnalytics/orea/app/oreapp.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,8 @@ void OREApp::initFromInputs() {
413413
// Initialise Singletons
414414
Settings::instance().evaluationDate() = inputs_->asof();
415415
InstrumentConventions::instance().setConventions(inputs_->conventions());
416+
if (inputs_->mporConventions() && inputs_->mporDate() != Date())
417+
InstrumentConventions::instance().setConventions(inputs_->mporConventions(), inputs_->mporDate());
416418

417419
if (inputs_->currencyConfigs() != nullptr)
418420
inputs_->currencyConfigs()->addCurrencies();
@@ -754,6 +756,10 @@ void OREAppInputParameters::loadParameters() {
754756
if (tmp != "")
755757
setImplyTodaysFixings(ore::data::parseBool(tmp));
756758

759+
tmp = params_->get("setup", "fixingCutOffDate", false);
760+
if (tmp != "")
761+
setFixingCutOffDate(ore::data::parseDate(tmp));
762+
757763
tmp = params_->get("setup", "useAtParCouponsCurves", false);
758764
if (tmp != "")
759765
setUseAtParCouponsCurves(ore::data::parseBool(tmp));

OREAnalytics/orea/scenario/historicalscenariogenerator.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class HistoricalScenarioGenerator : public ScenarioGenerator {
100100
const QuantLib::ext::shared_ptr<ore::data::AdjustmentFactors>& adjFactors = nullptr,
101101
//! string prepended to label of all scenarios generated
102102
const std::string& labelPrefix = "",
103-
//! indicates if the generated sceanrios will be absolute or difference
103+
//! indicates if the generated scenarios will be absolute or difference
104104
const bool generateDifferenceScenarios = false);
105105

106106
//! Set base scenario, this also defines the asof date

OREAnalytics/orea/scenario/scenarioutilities.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,10 +188,11 @@ QuantLib::ext::shared_ptr<Scenario> getDifferenceScenario(const QuantLib::ext::s
188188
QuantLib::ext::shared_ptr<Scenario> addDifferenceToScenario(const QuantLib::ext::shared_ptr<Scenario>& s,
189189
const QuantLib::ext::shared_ptr<Scenario>& d,
190190
const QuantLib::Date& targetScenarioAsOf,
191-
const QuantLib::Real targetScenarioNumeraire) {
191+
const QuantLib::Real targetScenarioNumeraire,
192+
const bool allowAdditionalKeysInD) {
192193

193194
QL_REQUIRE(!d->isAbsolute(), "addDifferenceToScenario(): second argument must be difference scenario");
194-
QL_REQUIRE(checkKeyDifferences(s, d, false),
195+
QL_REQUIRE(checkKeyDifferences(s, d, allowAdditionalKeysInD),
195196
"addDifferenceToScenario(): scenario key sets are not compatible. Check log for details.");
196197

197198
QuantLib::Date asof = targetScenarioAsOf;

OREAnalytics/orea/scenario/scenarioutilities.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ QuantLib::Real addDifferenceToScenario(const RiskFactorKey::KeyType keyType, con
4646
QuantLib::ext::shared_ptr<Scenario> addDifferenceToScenario(const QuantLib::ext::shared_ptr<Scenario>& s,
4747
const QuantLib::ext::shared_ptr<Scenario>& d,
4848
const QuantLib::Date& targetScenarioAsOf = QuantLib::Date(),
49-
const QuantLib::Real targetScenarioNumeraire = 0.0);
49+
const QuantLib::Real targetScenarioNumeraire = 0.0,
50+
const bool allowAdditionalKeysInD = false);
5051

5152
QuantLib::ext::shared_ptr<Scenario>
5253
recastScenario(const QuantLib::ext::shared_ptr<Scenario>& scenario,

OREAnalytics/orea/scenario/zerotoparscenariogenerator.cpp

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <orea/scenario/scenarioutilities.hpp>
2121
#include <orea/scenario/simplescenario.hpp>
2222
#include <orea/scenario/simplescenariofactory.hpp>
23+
#include <orea/engine/parsensitivityanalysis.hpp>
2324

2425
using namespace QuantLib;
2526

@@ -33,32 +34,50 @@ ZeroToParScenarioGenerator::ZeroToParScenarioGenerator(
3334
: HistoricalScenarioGenerator(hsg->scenarioLoader(), hsg->scenarioFactory(), hsg->returnConfiguration(),
3435
hsg->adjFactors(), hsg->labelPrefix(), hsg->generateDifferenceScenarios()) {
3536

36-
baseScenario_ = hsg->baseScenario();
37+
auto bs = hsg->baseScenario();
3738
shiftConverter_ = QuantLib::ext::make_shared<ZeroToParShiftConverter>(parInstruments, simMarket);
3839
auto baseValues = shiftConverter_->baseValues();
3940

40-
// build a base par scenario off the zero base scenario, and update with the calculated par rates
41-
baseParScenario_ = baseScenario_->clone();
41+
// build a base and base par scenario off the zero base scenario, and update with the calculated par rates
42+
// base scenario must be the minimum of the simulation (hsg baseScenario) and sensitivity configuration
43+
44+
baseScenario_ = QuantLib::ext::make_shared<SimpleScenario>(bs->asof(), bs->label(), bs->getNumeraire());
45+
baseParScenario_ = QuantLib::ext::make_shared<SimpleScenario>(bs->asof(), bs->label(), bs->getNumeraire());
4246
baseParScenario_->setPar(true);
43-
for (const auto& kv : baseValues)
44-
baseParScenario_->add(kv.first, kv.second);
47+
for (auto& k : bs->keys()) {
48+
auto bv = bs->get(k);
49+
if (ParSensitivityAnalysis::isParType(k.keytype)) {
50+
auto it = baseValues.find(k);
51+
if (it != baseValues.end()) {
52+
// found in par rates
53+
baseScenario_->add(k, bv);
54+
baseParScenario_->add(k, it->second);
55+
}
56+
} else {
57+
baseScenario_->add(k, bv);
58+
baseParScenario_->add(k, bv);
59+
}
60+
}
4561
}
4662

4763
QuantLib::ext::shared_ptr<Scenario> ZeroToParScenarioGenerator::next(const Date& d) {
4864
auto zeroScenario = HistoricalScenarioGenerator::next(d);
4965

5066
// create a par scenario to hold the par shifts
5167
QuantLib::ext::shared_ptr<Scenario> parScenario =
52-
addDifferenceToScenario(baseScenario_, zeroScenario, d, baseScenario_->getNumeraire());
68+
addDifferenceToScenario(baseScenario_, zeroScenario, d, baseScenario_->getNumeraire(), true);
5369
parScenario->setPar(true);
70+
parScenario->label(to_string(d));
5471

5572
// get the par shifts and update the par scenario
5673
auto parShifts = shiftConverter_->parShifts(zeroScenario);
5774
auto baseRates = shiftConverter_->baseValues();
5875

5976
for (const auto& kv : parShifts) {
60-
auto base = baseRates[kv.first];
61-
parScenario->add(kv.first, base + kv.second);
77+
if (baseScenario_->has(kv.first)) {
78+
auto base = baseRates[kv.first];
79+
parScenario->add(kv.first, base + kv.second);
80+
}
6281
}
6382

6483
return parScenario;

0 commit comments

Comments
 (0)