3
$\begingroup$

Is there a way I can get DV01 breakup of a Swap across different tenors of the deal in Quantlib-Python. The question asked here, follows the basic method of re-valuing the swap by shifting the curve through 1-bips and summing positive and negative impacts.

By the above method we can get net DV01, for each leg(fixed/float) of a derivative instrument. But if we drill-down we could see that net DV01 of a leg is an aggregration of differential DV01s accrued at tenor point where cash flow occurs (each cash flow tenor point might not have DV contribution). In short, we generally calculate Modified Duration, but I am looking for Key-rate Duration.

I have to create a hedge basket, where I get differential DV01s for each tenor points. Such that I can buy/sell instruments to net the PV impact for individual tenors.

As an illustration, this is how my Pricer provides tenor-wise DV01s. Sample tenor-wise DV01

Is there a function/module which does this, or it has to be created from the scratch. I have done the steps explained in this post, but it illustrates for a flat rate curve. I need to evaluate for a swap with floating rates. I am not sure how it will handle interpolation of floating rates.

$\endgroup$

1 Answer 1

2
$\begingroup$

You would have to "create it from scratch" although it's not too complicated. What you want to do is value your swap with your market curve and then revalue it after shifting each tenor. The difference between the market value and the value you get after bumping a particular tenor will be the key risk for that tenor.

There are different ways to do this. You could bump the zero rates, the par rates or forward rates.

In this example I am bumping the par rates.

import QuantLib as ql

today = ql.Date().todaysDate()
tenors = (1,2,3,4,5,6,7)
quotes = [ql.SimpleQuote(0.01) for n in tenors]
handles = [ql.QuoteHandle(quote) for quote in quotes]
dates = [today + ql.Period(y, ql.Years) for y in tenors]

helpers = []
yts = ql.RelinkableYieldTermStructureHandle()
euribor6m = ql.Euribor6M(yts)
for quote, tenor in zip(handles, tenors):
    helpers.append( ql.SwapRateHelper(quote,
                        ql.Period(tenor, ql.Years), ql.TARGET(),
                        ql.Annual, ql.Unadjusted,
                        ql.Thirty360(ql.Thirty360.BondBasis),
                        euribor6m)
                  )
curve = ql.PiecewiseLogCubicDiscount(0, ql.TARGET(), helpers, ql.Actual365Fixed())
yts.linkTo(curve)
engine = ql.DiscountingSwapEngine(yts)

swap = ql.MakeVanillaSwap(ql.Period('5y'), euribor6m, 0.01, ql.Period('0d'), Nominal=5e6)
swap.setPricingEngine(engine)

npv = swap.NPV()
key_risk = []
for quote in quotes:
    value = quote.value()
    quote.setValue(value + 0.0001)
    key_risk.append( npv - swap.NPV() )
    quote.setValue(value)

for tenor, risk in zip(tenors, key_risk):
    print("{}y: {:>12,.2f}".format(tenor, risk))

The output would be:

1y:         -0.00
2y:          0.00
3y:         -0.08
4y:          0.05
5y:     -2,426.15
6y:         -0.00
7y:         -0.00
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.