Skip to content

Commit 9cba820

Browse files
pcaspersjenkins
authored andcommitted
QPR-12114 extend regularization of diagonal elements from credit to rate curves, improve error reporting
1 parent 3ad9014 commit 9cba820

1 file changed

Lines changed: 39 additions & 14 deletions

File tree

OREAnalytics/orea/engine/parsensitivityanalysis.cpp

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -883,13 +883,19 @@ void ParSensitivityAnalysis::computeParInstrumentSensitivities(const boost::shar
883883

884884
// process par helpers
885885

886+
std::set<RiskFactorKey::KeyType> survivalAndRateCurveTypes = {
887+
RiskFactorKey::KeyType::SurvivalProbability, RiskFactorKey::KeyType::DiscountCurve,
888+
RiskFactorKey::KeyType::YieldCurve, RiskFactorKey::KeyType::IndexCurve};
889+
886890
for (auto const& p : parHelpers_) {
887891

888892
// skip if par helper has no sensi to zero risk factor (except the special treatment below kicks in)
889893

890894
if (p.second->isCalculated() &&
891-
(p.first.keytype != RiskFactorKey::KeyType::SurvivalProbability || p.first != desc[i].key1()))
895+
(survivalAndRateCurveTypes.find(p.first.keytype) == survivalAndRateCurveTypes.end() ||
896+
p.first != desc[i].key1())) {
892897
continue;
898+
}
893899

894900
// compute fair and base quotes
895901

@@ -901,14 +907,14 @@ void ParSensitivityAnalysis::computeParInstrumentSensitivities(const boost::shar
901907

902908
// special treatments for certain risk factors
903909

904-
// for curves with survival probabilities going to zero quickly we might see a sensitivity
905-
// that is close to zero, which we sanitise here in order to prevent the Jacobi matrix
910+
// for curves with survival probabilities / discount factors going to zero quickly we might see a
911+
// sensitivity that is close to zero, which we sanitise here in order to prevent the Jacobi matrix
906912
// getting ill-conditioned or even singular
907913

908-
if (p.first.keytype == RiskFactorKey::KeyType::SurvivalProbability && p.first == desc[i].key1() &&
909-
std::abs(tmp) < 0.01) {
910-
WLOG("Setting Diagonal Default Curve Sensi " << p.first << " w.r.t. " << desc[i].key1()
911-
<< " to 0.01 (got " << tmp << ")");
914+
if (survivalAndRateCurveTypes.find(p.first.keytype) != survivalAndRateCurveTypes.end() &&
915+
p.first == desc[i].key1() && std::abs(tmp) < 0.01) {
916+
WLOG("Setting Diagonal Sensi " << p.first << " w.r.t. " << desc[i].key1() << " to 0.01 (got " << tmp
917+
<< ")");
912918
tmp = 0.01;
913919
}
914920

@@ -1006,16 +1012,35 @@ void ParSensitivityAnalysis::computeParInstrumentSensitivities(const boost::shar
10061012
std::inserter(parKeysZero, parKeysZero.begin()));
10071013
std::set_difference(rawKeysCheck.begin(), rawKeysCheck.end(), rawKeysNonZero.begin(), rawKeysNonZero.end(),
10081014
std::inserter(rawKeysZero, rawKeysZero.begin()));
1009-
for (auto const& k : parKeysZero) {
1010-
WLOG("Found par instrument which has no sensitivity to any of the risk factors: \"" << k << "\"");
1011-
}
1012-
for (auto const& k : rawKeysZero) {
1013-
WLOG("Found risk factor w.r.t. which no par instrument has a sensitivity: \"" << k << "\"");
1015+
std::set<RiskFactorKey> problematicKeys;
1016+
problematicKeys.insert(parKeysZero.begin(), parKeysZero.end());
1017+
problematicKeys.insert(rawKeysZero.begin(), rawKeysZero.end());
1018+
for (auto const& k : problematicKeys) {
1019+
std::string type;
1020+
if (parKeysZero.find(k) != parKeysZero.end())
1021+
type = "par instrument is insensitive to all zero risk factors";
1022+
else if (rawKeysZero.find(k) != rawKeysZero.end())
1023+
type = "zero risk factor that does not affect an par instrument";
1024+
else
1025+
type = "unknown";
1026+
Real parHelperValue = Null<Real>();
1027+
if (auto tmp = parHelpers_.find(k); tmp != parHelpers_.end())
1028+
parHelperValue = impliedQuote(tmp->second);
1029+
else if (auto tmp = parCaps_.find(k); tmp != parCaps_.end())
1030+
parHelperValue = tmp->second->NPV();
1031+
else if (auto tmp = parYoYCaps_.find(k); tmp != parYoYCaps_.end())
1032+
parHelperValue = tmp->second->NPV();
1033+
Real zeroFactorValue = Null<Real>();
1034+
if (simMarket->baseScenarioAbsolute()->has(k))
1035+
zeroFactorValue = simMarket->baseScenarioAbsolute()->get(k);
1036+
WLOG("zero/par relation problem for key '"
1037+
<< k << "', type " + type + ", par value = "
1038+
<< (parHelperValue == Null<Real>() ? "na" : std::to_string(parHelperValue))
1039+
<< ", zero value = " << (zeroFactorValue == Null<Real>() ? "na" : std::to_string(zeroFactorValue)));
10141040
}
10151041

10161042
LOG("Computing par rate and flat vol sensitivities done");
1017-
1018-
} // namespace sensitivity
1043+
} // compute par instrument sensis
10191044

10201045
void ParSensitivityAnalysis::alignPillars() {
10211046
LOG("Align simulation market pillars to actual latest relevant dates of par instruments");

0 commit comments

Comments
 (0)