@@ -280,59 +280,32 @@ QuantLib::Real SimmConfigurationBase::correlation(const RiskType& firstRt, const
280280 return 1.0 ;
281281 }
282282
283- // Deal with case of different risk types
284- if ((firstRt != secondRt) && (firstQualifier == secondQualifier)) {
285- if (((firstRt == RiskType::IRCurve || firstRt == RiskType::Inflation) && secondRt == RiskType::XCcyBasis) ||
286- (firstRt == RiskType::XCcyBasis && (secondRt == RiskType::IRCurve || secondRt == RiskType::Inflation))) {
287- // Between xccy basis and any yield or inflation in same currency
288- return xccyCorr_;
289- }
290- if ((firstRt == RiskType::IRCurve && secondRt == RiskType::Inflation) ||
291- (firstRt == RiskType::Inflation && secondRt == RiskType::IRCurve)) {
292- // Between any yield and inflation in same currency
293- return infCorr_;
294- }
295- if ((firstRt == RiskType::IRVol && secondRt == RiskType::InflationVol) ||
296- (firstRt == RiskType::InflationVol && secondRt == RiskType::IRVol)) {
297- // Between any yield volatility and inflation volatility in same currency
298- return infVolCorr_;
299- }
300- }
283+ // Deal with Equity correlations
284+ if ((firstRt == RiskType::Equity && secondRt == RiskType::Equity) ||
285+ (firstRt == RiskType::EquityVol && secondRt == RiskType::EquityVol)) {
301286
302- // Deal with IRCurve and IRVol correlations
303- if ((firstRt == RiskType::IRCurve && secondRt == RiskType::IRCurve) ||
304- (firstRt == RiskType::IRVol && secondRt == RiskType::IRVol)) {
287+ // Get the bucket of each qualifier
288+ string bucket_1 = simmBucketMapper_-> bucket (firstRt, firstQualifier);
289+ string bucket_2 = simmBucketMapper_-> bucket ( secondRt, secondQualifier);
305290
306- // If the qualifiers, i.e. currencies, are the same
307- if (firstQualifier == secondQualifier) {
308- // Label2 level, i.e. sub-curve, correlations
309- if (firstLabel_2 != secondLabel_2) {
310- QL_REQUIRE (
311- firstLabel_1 == " " && secondLabel_1 == " " ,
312- " When asking for Label2 level correlations, "
313- << " the Label1 level values should both contain the default parameter i.e. empty string" );
314- QL_REQUIRE (firstRt != RiskType::IRVol, " There is no correlation at the Label2 level for Risk_IRVol" );
315- return irSubCurveCorr_;
316- }
291+ // Residual is special, 0 correlation inter and intra except if same qualifier
292+ if (bucket_1 == " Residual" || bucket_2 == " Residual" ) {
293+ return firstQualifier == secondQualifier ? 1.0 : 0.0 ;
294+ }
317295
318- // Label1 level, i.e. tenor, correlations
319- RiskType rt = RiskType::IRCurve;
320- auto label12Key = makeKey (" " , firstLabel_1, secondLabel_1);
321- if (intraBucketCorrelation_.at (rt).find (label12Key) != intraBucketCorrelation_.at (rt).end ())
322- return intraBucketCorrelation_.at (rt).at (label12Key);
323- else
324- QL_FAIL (" Could not find correlation for risk type " << rt << " and key " << label12Key);
296+ // Non-residual
297+ // Get the bucket index of each qualifier
298+ if (bucket_1 == bucket_2) {
299+ auto bucketKey = makeKey (bucket_1, " " , " " );
300+ // If same bucket, return the intra-bucket correlation
301+ return firstQualifier == secondQualifier ? 1.0 : intraBucketCorrelation_.at (RiskType::Equity).at (bucketKey);
325302 } else {
326- // If the qualifiers, i.e. currencies, are not the same
327- return irInterCurrencyCorr_;
303+ // If different buckets, return the inter-bucket correlation
304+ auto label12Key = makeKey (" " , bucket_1, bucket_2);
305+ return interBucketCorrelation_.at (RiskType::Equity).at (label12Key);
328306 }
329307 }
330308
331- // Deal with inflation volatility correlations
332- if (firstRt == RiskType::InflationVol && secondRt == RiskType::InflationVol) {
333- return 1.0 ;
334- }
335-
336309 // Deal with CreditQ correlations
337310 if ((firstRt == RiskType::CreditQ && secondRt == RiskType::CreditQ) ||
338311 (firstRt == RiskType::CreditVol && secondRt == RiskType::CreditVol)) {
@@ -413,32 +386,6 @@ QuantLib::Real SimmConfigurationBase::correlation(const RiskType& firstRt, const
413386 }
414387 }
415388
416- // Deal with Equity correlations
417- if ((firstRt == RiskType::Equity && secondRt == RiskType::Equity) ||
418- (firstRt == RiskType::EquityVol && secondRt == RiskType::EquityVol)) {
419-
420- // Get the bucket of each qualifier
421- string bucket_1 = simmBucketMapper_->bucket (firstRt, firstQualifier);
422- string bucket_2 = simmBucketMapper_->bucket (secondRt, secondQualifier);
423-
424- // Residual is special, 0 correlation inter and intra except if same qualifier
425- if (bucket_1 == " Residual" || bucket_2 == " Residual" ) {
426- return firstQualifier == secondQualifier ? 1.0 : 0.0 ;
427- }
428-
429- // Non-residual
430- // Get the bucket index of each qualifier
431- if (bucket_1 == bucket_2) {
432- auto bucketKey = makeKey (bucket_1, " " , " " );
433- // If same bucket, return the intra-bucket correlation
434- return firstQualifier == secondQualifier ? 1.0 : intraBucketCorrelation_.at (RiskType::Equity).at (bucketKey);
435- } else {
436- // If different buckets, return the inter-bucket correlation
437- auto label12Key = makeKey (" " , bucket_1, bucket_2);
438- return interBucketCorrelation_.at (RiskType::Equity).at (label12Key);
439- }
440- }
441-
442389 // Deal with Commodity correlations
443390 if ((firstRt == RiskType::Commodity && secondRt == RiskType::Commodity) ||
444391 (firstRt == RiskType::CommodityVol && secondRt == RiskType::CommodityVol)) {
@@ -458,6 +405,59 @@ QuantLib::Real SimmConfigurationBase::correlation(const RiskType& firstRt, const
458405 }
459406 }
460407
408+ // Deal with case of different risk types
409+ if ((firstRt != secondRt) && (firstQualifier == secondQualifier)) {
410+ if (((firstRt == RiskType::IRCurve || firstRt == RiskType::Inflation) && secondRt == RiskType::XCcyBasis) ||
411+ (firstRt == RiskType::XCcyBasis && (secondRt == RiskType::IRCurve || secondRt == RiskType::Inflation))) {
412+ // Between xccy basis and any yield or inflation in same currency
413+ return xccyCorr_;
414+ }
415+ if ((firstRt == RiskType::IRCurve && secondRt == RiskType::Inflation) ||
416+ (firstRt == RiskType::Inflation && secondRt == RiskType::IRCurve)) {
417+ // Between any yield and inflation in same currency
418+ return infCorr_;
419+ }
420+ if ((firstRt == RiskType::IRVol && secondRt == RiskType::InflationVol) ||
421+ (firstRt == RiskType::InflationVol && secondRt == RiskType::IRVol)) {
422+ // Between any yield volatility and inflation volatility in same currency
423+ return infVolCorr_;
424+ }
425+ }
426+
427+ // Deal with IRCurve and IRVol correlations
428+ if ((firstRt == RiskType::IRCurve && secondRt == RiskType::IRCurve) ||
429+ (firstRt == RiskType::IRVol && secondRt == RiskType::IRVol)) {
430+
431+ // If the qualifiers, i.e. currencies, are the same
432+ if (firstQualifier == secondQualifier) {
433+ // Label2 level, i.e. sub-curve, correlations
434+ if (firstLabel_2 != secondLabel_2) {
435+ QL_REQUIRE (
436+ firstLabel_1 == " " && secondLabel_1 == " " ,
437+ " When asking for Label2 level correlations, "
438+ << " the Label1 level values should both contain the default parameter i.e. empty string" );
439+ QL_REQUIRE (firstRt != RiskType::IRVol, " There is no correlation at the Label2 level for Risk_IRVol" );
440+ return irSubCurveCorr_;
441+ }
442+
443+ // Label1 level, i.e. tenor, correlations
444+ RiskType rt = RiskType::IRCurve;
445+ auto label12Key = makeKey (" " , firstLabel_1, secondLabel_1);
446+ if (intraBucketCorrelation_.at (rt).find (label12Key) != intraBucketCorrelation_.at (rt).end ())
447+ return intraBucketCorrelation_.at (rt).at (label12Key);
448+ else
449+ QL_FAIL (" Could not find correlation for risk type " << rt << " and key " << label12Key);
450+ } else {
451+ // If the qualifiers, i.e. currencies, are not the same
452+ return irInterCurrencyCorr_;
453+ }
454+ }
455+
456+ // Deal with inflation volatility correlations
457+ if (firstRt == RiskType::InflationVol && secondRt == RiskType::InflationVol) {
458+ return 1.0 ;
459+ }
460+
461461 // Deal with FX correlations
462462 // TODO:
463463 // For FXVol, qualifier is a currency pair. Is it possible to get here
0 commit comments