Estimating Bond Key-Tenor DV01 with Curve Bumps in QuantLib
Summary
The document describes how to estimate a bond’s sensitivity to individual spot-curve tenor points, a measure useful for building a tenor-based risk profile for a bond portfolio. It distinguishes tenor DV01—the change in market value for a one-basis-point shift at a selected tenor—from PV01, which can refer to the present value of one basis point.
The method constructs a spreaded yield curve with a separate quote at each tenor, prices a fixed-rate bond, then bumps each quote upward by one basis point in turn and records the resulting change in net present value. Resetting each quote after its bump isolates the bond’s sensitivity to that curve point. The answer notes that interpolation between curve tenors affects the result, and suggests averaging the market-value changes from upward and downward shifts for a more balanced estimate. The example illustrates the calculation but does not provide a full portfolio VaR workflow or discuss calibration choices.
Key ideas
- Key-tenor DV01 measures bond value change from a one-basis-point shift at a particular curve tenor.
- Create a separate curve quote for each tenor and bump them one at a time.
- Record the bond’s NPV change after each bump to estimate its key-rate sensitivity.
- Curve interpolation affects how tenor-specific shifts influence bond value.
- Averaging upward and downward bump results can provide a balanced sensitivity estimate.
Tags
Full text
# Quantlib Bond PV01 by Tenor
# Quantlib Bond PV01 by Tenor
Having built a fixed rate bond object, and looking at here and here , is there any way of retrieving the NPV impact of a repriced bond by bucket/tenor of the Spot Curve instead of getting a simple NPV figure? The objective of this would be to have a baseline to apply a simple Value at Risk model to a portfolio of bonds, in which the key risk factors would be the -PV01 figures by tenor.
## Answer by David Duarte (score 3, accepted)
https://quant.stackexchange.com/a/50720
There is a way, although you will have to code the logic. I'm assuming you want the tenor DV01 (change of market value for a shift of 1 bp in the market rate for a given tenor) and not the PV01 (present value of 1 bp).
Also, bear in mind Luigi's warning on the interpolation between the curve tenor points in one of the posts you mentioned.
```
import QuantLib as ql
import matplotlib.pyplot as plt
today = ql.Date().todaysDate()
ql.Settings.instance().evaluationDate = today
yts = ql.YieldTermStructureHandle(
ql.FlatForward(today, 0.01, ql.Actual365Fixed())
)
tenors = (1,2,3,4,5,6,7)
quotes = [ql.SimpleQuote(0.00) for n in tenors]
spreads = [ql.QuoteHandle(quote) for quote in quotes]
dates = [today + ql.Period(y, ql.Years) for y in tenors]
spreadedYts = ql.YieldTermStructureHandle(
ql.SpreadedLinearZeroInterpolatedTermStructure(yts, spreads, dates)
)
engine = ql.DiscountingBondEngine(spreadedYts)
bond = ql.FixedRateBond(2, ql.TARGET(), 1e6, today, today + ql.Period(5, ql.Years), ql.Period('1Y'), [0.01], ql.ActualActual())
bond.setPricingEngine(engine)
npv = bond.NPV()
key_risk = []
for quote in quotes:
quote.setValue(0.0001)
key_risk.append( npv - bond.NPV() )
quote.setValue(0.0)
plt.bar(tenors, key_risk)
```
Which would output:
You might also want to calculate it as the average of the change of market value for an up shift and a down shiftShown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.