QuantLib: Building Key Rate Risks
Asked Answered
J

1

5

I was able to build a discount curve for the Treasury market. However, I'm looking to use this to find the key rate risks of an individual bond (and eventually a portfolio of bonds).

The key rate risk I'm looking for is if I have a 30Y bond and we shift the 1y rate that was used to discount the bond, while holding the other rates constant, how much does the price of the bond change by? Repeating this for the tenors (eg. 2Y, 5Y, 7Y, etc) and summing the result should get you to the overall duration of the bond, but provides a better view of how the risk exposure breaks down.

http://www.investinganswers.com/financial-dictionary/bonds/key-rate-duration-6725

Is anyone aware of any documentation that demonstrates how to do this? Thank you.

Jessikajessup answered 18/9, 2017 at 12:53 Comment(0)
G
8

Given that you have already built the bond and the discount curve, and you have linked them in some way similar to:

discount_handle = RelinkableYieldTermStructureHandle(discount_curve)

bond.setPricingEngine(DiscountingBondEngine(discount_handle))

you can first add a spread over the existing discount curve and then use the modified curve to price the bond. Something like:

nodes = [ 1, 2, 5, 7, 10 ]  # the durations
dates = [ today + Period(n, Years) for n in nodes ]
spreads = [ SimpleQuote(0.0) for n in nodes ] # null spreads to begin

new_curve = SpreadedLinearZeroInterpolatedTermStructure(
    YieldTermStructureHandle(discount_curve),
    [ QuoteHandle(q) for q in spreads ],
    dates)

will give you a new curve with initial spreads all at 0 (and a horrible class name) that you can use instead of the original discount curve:

discount_handle.linkTo(new_curve)

After the above, the bond should still return the same price (since the spreads are all null).

When you want to calculate a particular key-rate duration, you can move the corresponding quote: for instance, if you want to bump the 5-years quote (the third in the list above), execute

spreads[2].setValue(0.001)   # 10 bps

the curve will update accordingly, and the bond price should change.

A note: the above will interpolate between spreads, so if you move the 5-years points by 10 bps and you leave the 2-years point unchanged, then a rate around 3 years would move by about 3 bps. To mitigate this (in case that's not what you want), you can add more points to the curve and restrict the range that varies. For instance, if you add a point at 5 years minus one month and another at 5 years plus 1 month, then moving the 5-years point will only affect the two months around it.

Grantland answered 22/9, 2017 at 13:34 Comment(6)
Thanks so much for your response Luigi. Needless to say, your package and tips are extremely helpful. Apologies for my ignorance with this as I'm still trying to learn the structure, but is there a way to have the spreads[2].setValue(0.001) update the curve in place? Off your answer above, once I execute the following discount_handle.linkTo(new_curve) spreads[2].setValue(0.001) fixed_rate_bond.setPricingEngine(new_curve) print(fixed_rate_bond.NPV()) I'm still receiving the same NPV as before the setValue(). Is this to be expected?Jessikajessup
It should update in place. Please post your code to the QuantLib mailing list, we'll try to figure it out.Grantland
Not sure how to post on sourceforge if that's where you are referencing. Is there an e-mail distribution I can send it to? Thank you.Jessikajessup
You can post to the QuantLib mailing list at the address <[email protected]>.Grantland
@LuigiBallabio I'm also experiencing the same problem with the NPV not updating after using .setValue(). I'm using version 1.12Bossism
Please post your code to the QuantLib mailing list, we'll try to figure it out.Grantland

© 2022 - 2024 — McMap. All rights reserved.