Bond Risk Measures and Immunization › Portfolio Duration and Convexity
Quantitative FinanceAll chapters Bond Risk Measures and Immunization › Portfolio Duration and ConvexityOne section · Sections in this chapter7 / 13 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
Individual bond risk measures become even more powerful when extended to portfolios. A portfolio manager holding dozens or hundreds of bonds needs a way to summarize the aggregate interest rate exposure. Fortunately, duration and convexity combine in a straightforward way: they are computed as weighted averages, where the weights are each bond's market value as a proportion of total portfolio value.
For a portfolio with bonds, each with market value and modified duration :
where:
- : the portfolio's modified duration
- : the weight of bond in the portfolio, calculated as
- : the market value of bond
- : the modified duration of bond
- : the number of bonds in the portfolio
This formula follows from the linearity of the price change approximation. If each bond's percentage price change is given by , then the portfolio's percentage change is the value-weighted average of the individual changes. The same weighting applies to convexity:
where is the convexity of bond .
This weighted-average approach allows portfolio managers to adjust interest rate exposure by changing the mix of bonds. With positive portfolio value and a positive-value addition, holding the other positions fixed, a bond whose modified duration exceeds the current portfolio duration raises it; one below the current portfolio duration lowers it. These comparisons use the same yield-change coordinate.
def portfolio_duration_convexity(bonds_data, yield_rate):
"""
Calculate portfolio duration and convexity.
bonds_data: list of dicts with 'face_value', 'coupon_rate', 'maturity', 'quantity'
"""
results = []
total_value = 0
for bond in bonds_data:
price_i = bond_price(
bond["face_value"],
bond["coupon_rate"],
bond["maturity"],
yield_rate,
)
value_i = price_i * bond["quantity"]
dur_i = modified_duration(
bond["face_value"],
bond["coupon_rate"],
bond["maturity"],
yield_rate,
)
conv_i = convexity(
bond["face_value"],
bond["coupon_rate"],
bond["maturity"],
yield_rate,
)
results.append(
{
"price": price_i,
"value": value_i,
"duration": dur_i,
"convexity": conv_i,
}
)
total_value += value_i
# Calculate weighted averages
port_duration = sum(r["value"] * r["duration"] for r in results) / total_value
port_convexity = sum(r["value"] * r["convexity"] for r in results) / total_value
return port_duration, port_convexity, total_value, results# Create a sample portfolio
portfolio = [
{
"face_value": 1000,
"coupon_rate": 0.03,
"maturity": 2,
"quantity": 100,
"name": "2-year, 3%",
},
{
"face_value": 1000,
"coupon_rate": 0.04,
"maturity": 5,
"quantity": 150,
"name": "5-year, 4%",
},
{
"face_value": 1000,
"coupon_rate": 0.05,
"maturity": 10,
"quantity": 100,
"name": "10-year, 5%",
},
{
"face_value": 1000,
"coupon_rate": 0.055,
"maturity": 30,
"quantity": 50,
"name": "30-year, 5.5%",
},
]
yield_rate = 0.05
port_dur, port_conv, total_val, details = portfolio_duration_convexity(
portfolio, yield_rate
)
print("Portfolio Composition")
print("=" * 75)
print(
f"{'Bond':<15} {'Price':>10} {'Quantity':>10} {'Value':>12} {'Duration':>10} {'Weight':>10}"
)
print("-" * 75)
for bond, det in zip(portfolio, details):
weight = det["value"] / total_val * 100
print(
f"{bond['name']:<15} ${det['price']:>9.2f} {bond['quantity']:>10} ${det['value']:>11,.2f} {det['duration']:>10.2f} {weight:>9.1f}%"
)
print("-" * 75)
print(f"{'Total':<15} {'':<10} {'':<10} ${total_val:>11,.2f}")
print(f"\nPortfolio Duration: {port_dur:.2f}")
print(f"Portfolio Convexity: {port_conv:.2f}")Portfolio Composition =========================================================================== Bond Price Quantity Value Duration Weight --------------------------------------------------------------------------- 2-year, 3% $ 962.38 100 $ 96,238.03 1.91 24.5% 5-year, 4% $ 956.24 150 $ 143,435.95 4.46 36.4% 10-year, 5% $ 1000.00 100 $ 100,000.00 7.79 25.4% 30-year, 5.5% $ 1077.27 50 $ 53,863.58 15.16 13.7% --------------------------------------------------------------------------- Total $ 393,537.56 Portfolio Duration: 6.15 Portfolio Convexity: 74.98
The portfolio's modified duration is approximately 6.15 years, the market-value-weighted average of the individual modified durations. The thirty-year bond has the longest modified duration, about 15.16 years, but represents only 13.69% of portfolio value. Portfolio convexity is about 74.98. For a small common yield change, these measures give the portfolio's first- and second-order price approximation; positive convexity does not prevent a loss when yields rise.

