@@ -231,59 +231,32 @@ QuantLib::Real SimmConfigurationBase::correlation(const RiskType& firstRt, const
231231 return 1.0 ;
232232 }
233233
234- // Deal with case of different risk types
235- if ((firstRt != secondRt) && (firstQualifier == secondQualifier)) {
236- if (((firstRt == RiskType::IRCurve || firstRt == RiskType::Inflation) && secondRt == RiskType::XCcyBasis) ||
237- (firstRt == RiskType::XCcyBasis && (secondRt == RiskType::IRCurve || secondRt == RiskType::Inflation))) {
238- // Between xccy basis and any yield or inflation in same currency
239- return xccyCorr_;
240- }
241- if ((firstRt == RiskType::IRCurve && secondRt == RiskType::Inflation) ||
242- (firstRt == RiskType::Inflation && secondRt == RiskType::IRCurve)) {
243- // Between any yield and inflation in same currency
244- return infCorr_;
245- }
246- if ((firstRt == RiskType::IRVol && secondRt == RiskType::InflationVol) ||
247- (firstRt == RiskType::InflationVol && secondRt == RiskType::IRVol)) {
248- // Between any yield volatility and inflation volatility in same currency
249- return infVolCorr_;
250- }
251- }
234+ // Deal with Equity correlations
235+ if ((firstRt == RiskType::Equity && secondRt == RiskType::Equity) ||
236+ (firstRt == RiskType::EquityVol && secondRt == RiskType::EquityVol)) {
252237
253- // Deal with IRCurve and IRVol correlations
254- if ((firstRt == RiskType::IRCurve && secondRt == RiskType::IRCurve) ||
255- (firstRt == RiskType::IRVol && secondRt == RiskType::IRVol)) {
238+ // Get the bucket of each qualifier
239+ string bucket_1 = simmBucketMapper_-> bucket (firstRt, firstQualifier);
240+ string bucket_2 = simmBucketMapper_-> bucket ( secondRt, secondQualifier);
256241
257- // If the qualifiers, i.e. currencies, are the same
258- if (firstQualifier == secondQualifier) {
259- // Label2 level, i.e. sub-curve, correlations
260- if (firstLabel_2 != secondLabel_2) {
261- QL_REQUIRE (
262- firstLabel_1 == " " && secondLabel_1 == " " ,
263- " When asking for Label2 level correlations, "
264- << " the Label1 level values should both contain the default parameter i.e. empty string" );
265- QL_REQUIRE (firstRt != RiskType::IRVol, " There is no correlation at the Label2 level for Risk_IRVol" );
266- return irSubCurveCorr_;
267- }
242+ // Residual is special, 0 correlation inter and intra except if same qualifier
243+ if (bucket_1 == " Residual" || bucket_2 == " Residual" ) {
244+ return firstQualifier == secondQualifier ? 1.0 : 0.0 ;
245+ }
268246
269- // Label1 level, i.e. tenor, correlations
270- RiskType rt = RiskType::IRCurve;
271- auto label12Key = makeKey (" " , firstLabel_1, secondLabel_1);
272- if (intraBucketCorrelation_.at (rt).find (label12Key) != intraBucketCorrelation_.at (rt).end ())
273- return intraBucketCorrelation_.at (rt).at (label12Key);
274- else
275- QL_FAIL (" Could not find correlation for risk type " << rt << " and key " << label12Key);
247+ // Non-residual
248+ // Get the bucket index of each qualifier
249+ if (bucket_1 == bucket_2) {
250+ auto bucketKey = makeKey (bucket_1, " " , " " );
251+ // If same bucket, return the intra-bucket correlation
252+ return firstQualifier == secondQualifier ? 1.0 : intraBucketCorrelation_.at (RiskType::Equity).at (bucketKey);
276253 } else {
277- // If the qualifiers, i.e. currencies, are not the same
278- return irInterCurrencyCorr_;
254+ // If different buckets, return the inter-bucket correlation
255+ auto label12Key = makeKey (" " , bucket_1, bucket_2);
256+ return interBucketCorrelation_.at (RiskType::Equity).at (label12Key);
279257 }
280258 }
281259
282- // Deal with inflation volatility correlations
283- if (firstRt == RiskType::InflationVol && secondRt == RiskType::InflationVol) {
284- return 1.0 ;
285- }
286-
287260 // Deal with CreditQ correlations
288261 if ((firstRt == RiskType::CreditQ && secondRt == RiskType::CreditQ) ||
289262 (firstRt == RiskType::CreditVol && secondRt == RiskType::CreditVol)) {
@@ -364,32 +337,6 @@ QuantLib::Real SimmConfigurationBase::correlation(const RiskType& firstRt, const
364337 }
365338 }
366339
367- // Deal with Equity correlations
368- if ((firstRt == RiskType::Equity && secondRt == RiskType::Equity) ||
369- (firstRt == RiskType::EquityVol && secondRt == RiskType::EquityVol)) {
370-
371- // Get the bucket of each qualifier
372- string bucket_1 = simmBucketMapper_->bucket (firstRt, firstQualifier);
373- string bucket_2 = simmBucketMapper_->bucket (secondRt, secondQualifier);
374-
375- // Residual is special, 0 correlation inter and intra except if same qualifier
376- if (bucket_1 == " Residual" || bucket_2 == " Residual" ) {
377- return firstQualifier == secondQualifier ? 1.0 : 0.0 ;
378- }
379-
380- // Non-residual
381- // Get the bucket index of each qualifier
382- if (bucket_1 == bucket_2) {
383- auto bucketKey = makeKey (bucket_1, " " , " " );
384- // If same bucket, return the intra-bucket correlation
385- return firstQualifier == secondQualifier ? 1.0 : intraBucketCorrelation_.at (RiskType::Equity).at (bucketKey);
386- } else {
387- // If different buckets, return the inter-bucket correlation
388- auto label12Key = makeKey (" " , bucket_1, bucket_2);
389- return interBucketCorrelation_.at (RiskType::Equity).at (label12Key);
390- }
391- }
392-
393340 // Deal with Commodity correlations
394341 if ((firstRt == RiskType::Commodity && secondRt == RiskType::Commodity) ||
395342 (firstRt == RiskType::CommodityVol && secondRt == RiskType::CommodityVol)) {
@@ -409,6 +356,59 @@ QuantLib::Real SimmConfigurationBase::correlation(const RiskType& firstRt, const
409356 }
410357 }
411358
359+ // Deal with case of different risk types
360+ if ((firstRt != secondRt) && (firstQualifier == secondQualifier)) {
361+ if (((firstRt == RiskType::IRCurve || firstRt == RiskType::Inflation) && secondRt == RiskType::XCcyBasis) ||
362+ (firstRt == RiskType::XCcyBasis && (secondRt == RiskType::IRCurve || secondRt == RiskType::Inflation))) {
363+ // Between xccy basis and any yield or inflation in same currency
364+ return xccyCorr_;
365+ }
366+ if ((firstRt == RiskType::IRCurve && secondRt == RiskType::Inflation) ||
367+ (firstRt == RiskType::Inflation && secondRt == RiskType::IRCurve)) {
368+ // Between any yield and inflation in same currency
369+ return infCorr_;
370+ }
371+ if ((firstRt == RiskType::IRVol && secondRt == RiskType::InflationVol) ||
372+ (firstRt == RiskType::InflationVol && secondRt == RiskType::IRVol)) {
373+ // Between any yield volatility and inflation volatility in same currency
374+ return infVolCorr_;
375+ }
376+ }
377+
378+ // Deal with IRCurve and IRVol correlations
379+ if ((firstRt == RiskType::IRCurve && secondRt == RiskType::IRCurve) ||
380+ (firstRt == RiskType::IRVol && secondRt == RiskType::IRVol)) {
381+
382+ // If the qualifiers, i.e. currencies, are the same
383+ if (firstQualifier == secondQualifier) {
384+ // Label2 level, i.e. sub-curve, correlations
385+ if (firstLabel_2 != secondLabel_2) {
386+ QL_REQUIRE (
387+ firstLabel_1 == " " && secondLabel_1 == " " ,
388+ " When asking for Label2 level correlations, "
389+ << " the Label1 level values should both contain the default parameter i.e. empty string" );
390+ QL_REQUIRE (firstRt != RiskType::IRVol, " There is no correlation at the Label2 level for Risk_IRVol" );
391+ return irSubCurveCorr_;
392+ }
393+
394+ // Label1 level, i.e. tenor, correlations
395+ RiskType rt = RiskType::IRCurve;
396+ auto label12Key = makeKey (" " , firstLabel_1, secondLabel_1);
397+ if (intraBucketCorrelation_.at (rt).find (label12Key) != intraBucketCorrelation_.at (rt).end ())
398+ return intraBucketCorrelation_.at (rt).at (label12Key);
399+ else
400+ QL_FAIL (" Could not find correlation for risk type " << rt << " and key " << label12Key);
401+ } else {
402+ // If the qualifiers, i.e. currencies, are not the same
403+ return irInterCurrencyCorr_;
404+ }
405+ }
406+
407+ // Deal with inflation volatility correlations
408+ if (firstRt == RiskType::InflationVol && secondRt == RiskType::InflationVol) {
409+ return 1.0 ;
410+ }
411+
412412 // Deal with FX correlations
413413 // TODO:
414414 // For FXVol, qualifier is a currency pair. Is it possible to get here
0 commit comments