Conversation
Under flipViewXVA PostProcess::updateNettingSetKVA() swapped the PD/LGD sources of the two KVA branches by overwriting dvaName_ per netting set, while the PD floors and the KVA-CVA risk weights stayed attached to the output column. Make the party identity explicit per netting set, derive PD, LGD, floor and risk weight of the "our" branch from the active counterparty and of the "their" branch from the active own party, and never write dvaName_, which also repairs the flipped CVA sensitivities. Normal view results are unchanged. Add KvaTest covering the flip view mirror, multi-counterparty and netting set order invariance and the CVA sensitivities, and clarify the kva parameter semantics in the user guide. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q5n2ExoAFe9qtbybzMxnsQ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #359.
With
flipViewXVA=Y,PostProcess::updateNettingSetKVA()swapped the PD/LGD sources of the two KVA branches but left the PD floors and the KVA-CVA risk weights attached to the output column, and it did the swap by overwriting the memberdvaName_with the current counterparty inside the netting-set loop. From the second netting set on, "our" KVA was therefore computed against the previous netting set's counterparty curve, andupdateNettingSetCvaSensitivity(), which runs next and readsdvaName_under flip, inherited the last counterparty's name too.The fix makes the party identity explicit per netting set:
bank = {dvaName, kvaOurPdFloor, kvaOurCvaRiskWeight},cpty = {counterparty(nettingSet), kvaTheirPdFloor, kvaTheirCvaRiskWeight}, thenactiveOwnParty = flip ? cpty : bankandactiveCounterparty = flip ? bank : cpty. Branch 1 (OurKVA*) takes PD, LGD, floor and risk weight fromactiveCounterparty, branch 2 (TheirKVA*) fromactiveOwnParty.dvaName_is no longer written, which also repairs the CVA sensitivities without touching that function. In normal view the inputs of every arithmetic operation are the same as before, so results there are unchanged. AQL_REQUIREnow names the problem whenflipViewXVAis set withoutdvaNameinstead of failing on an empty curve lookup. The user guide entry for thekva*parameters states which partyOur/Theirrefer to under flip.Tests (
OREAnalytics/test/kva.cpp, suiteKvaTest, no simulation: a hand-filled two-sample cube on uncollateralised netting sets, a three-name flat-hazard market, own/their floors 0.15/0.03 with the own floor binding, risk weights 0.02/0.05):Our*equals normalTheir*and vice versa for KVA-CCR and KVA-CVA (exact mirror, 1e-12 relative), plus the normal-view numbers pinned to the values produced before this change;kvaanalytic.Before the fix these fail with the expected fingerprints (18 failures: CCR mirror off by the floor, CVA mirror off by the risk-weight ratio 2.5, multi-counterparty and ordering cases off through the leaked name, sensitivities off through the leaked name); after the fix all pass and the pinned normal-view values are unchanged.
Verified with the
orebinary on the issue's reproduction (shipped flip-view example,kva=Y, uncollateralised, BANK at 3 % CDS, user-guide parameter values): after the fixOurKVACCR/TheirKVACCR/OurKVACVA/TheirKVACVAflipped equalTheirKVACCR/OurKVACCR/TheirKVACVA/OurKVACVAnormal to the cent, CPTY_B's flipped KVA is identical alone and together with CPTY_A, and the normal-viewxva.csvof both portfolios is byte-identical to the one produced before the fix.Not changed:
ValueAdjustmentCalculator::build()already isolates its loops with anorigDvaNamesnapshot, so CVA/DVA/FVA were not affected and are untouched. No shipped example enableskva, so no expected output changes.