DEV Community

pickuma
pickuma

Posted on • Originally published at pickuma.com

Bond Investing for Developers: Duration, Yield Curves, and Why Fixed Income Isn't Boring

For the first five years I invested, I owned exactly zero bonds. The reasoning was simple: stocks return 9% per year on average, bonds return 3%, why would I allocate capital to the lower-returning asset? I was not alone in this — most developers I know who started investing after 2010 built 100% equity portfolios. The 2022 bond market crash, where long-term Treasuries lost 30% while stocks also dropped, seemed to validate the "bonds are pointless" thesis.

The flaw in this reasoning is not mathematical but mental-model-level. Bonds are not a lower-return substitute for stocks. They are a different instrument with different return drivers, different risk characteristics, and a different role in a portfolio. Understanding those differences — and the bond math that governs them — is what separates someone who reacts to market moves from someone who anticipated them. Here is what I wish I had understood about bonds when I started.

Bonds Are Just Loans With Price Tags

A bond is a contract: you lend money to an entity (US Treasury, corporation, municipality) and they pay you interest for a fixed period, then return your principal at maturity. That is it. The complexity comes from the fact that bonds trade on secondary markets, so their price fluctuates between issuance and maturity based on interest rate changes.

The relationship is mechanical and deterministic, not probabilistic like stock returns. If you buy a 10-year Treasury bond yielding 4% and rates rise to 5%, the market value of your bond drops because new bonds pay more. The price must fall until the effective yield on your discounted bond matches the new market rate. This is not the market "panicking" — it is the mathematical consequence of fixed cash flows discounted at a higher rate.

For a developer, the mental model that clicks: a bond is a function that takes a discount rate as input and returns a present value. When the discount rate changes, the present value changes deterministically:

def bond_price(face_value, coupon_rate, years, yield_to_maturity, payments_per_year=2):
    periods = int(years * payments_per_year)
    coupon = face_value * coupon_rate / payments_per_year
    ytm_period = yield_to_maturity / payments_per_year

    pv_coupons = sum([coupon / (1 + ytm_period) ** t for t in range(1, periods + 1)])
    pv_face = face_value / (1 + ytm_period) ** periods

    return pv_coupons + pv_face

# $1,000 face value, 4% coupon, 10-year, yielding 5%
price = bond_price(1000, 0.04, 10, 0.05)
print(f"Bond price: ${price:.2f}")  # ~$922
Enter fullscreen mode Exit fullscreen mode

That 10-line function captures the core of fixed-income pricing. Play with the yield_to_maturity parameter and watch the price move — a 1% rate increase on a 10-year bond reduces its price by roughly 7-8%. That sensitivity is what the next concept, duration, quantifies.

Duration: The Number That Explains Everything

Duration measures a bond's price sensitivity to interest rate changes. Modified duration tells you the approximate percentage price change for a 1% parallel shift in yields. A bond with modified duration of 7 will lose roughly 7% if rates rise 1%, and gain roughly 7% if they fall 1%.

Calculating it:

def modified_duration(face_value, coupon_rate, years, yield_to_maturity):
    epsilon = 0.0001  # 1 basis point shock
    price_up = bond_price(face_value, coupon_rate, years, yield_to_maturity + epsilon)
    price_down = bond_price(face_value, coupon_rate, years, yield_to_maturity - epsilon)
    price_current = bond_price(face_value, coupon_rate, years, yield_to_maturity)
    return (price_down - price_up) / (2 * epsilon * price_current)

dur = modified_duration(1000, 0.04, 10, 0.05)
print(f"Modified duration: {dur:.2f}")
Enter fullscreen mode Exit fullscreen mode

The intuition that matters for portfolio construction: longer maturity = higher duration = more rate sensitivity. A 30-year Treasury bond has roughly three times the duration risk of a 10-year. If you expect rates to rise, shorten duration. If you expect rates to fall, extend it. This is the single most important tactical decision in fixed-income investing, and it is entirely separate from the credit quality decision (Treasury vs. corporate vs. junk).

warning

Duration is a linear approximation. For large rate moves — think 2% or more — duration underestimates the price change because of convexity. A bond with positive convexity (most standard bonds) loses less than duration predicts when rates rise and gains more when rates fall. Duration is accurate for small moves; for scenario analysis on large rate shocks, use the full bond_price function rather than the duration approximation.

The Yield Curve as a State Machine

The yield curve — a plot of Treasury yields across maturities from 1 month to 30 years — is the single best summary of bond market sentiment. Normally, longer maturities yield more: a 10-year bond pays more than a 2-year because you are taking more interest rate risk. When the curve inverts (2-year yields > 10-year yields), the bond market is pricing in a recession.

You can pull yield curve data from the US Treasury's public API:

import requests
import xml.etree.ElementTree as ET

url = ("https://home.treasury.gov/resource-center/"
       "data-chart-center/interest-rates/pages/"
       "xml?data=daily_treasury_yield_curve&field_tdr_date_value=2026")
resp = requests.get(url)
root = ET.fromstring(resp.content)

for entry in root.findall('.//{http://www.w3.org/2005/Atom}entry'):
    # Extract maturity and yield from each entry
    pass  # Implementation depends on response structure
Enter fullscreen mode Exit fullscreen mode

For a simpler approach, the FRED API (covered in a separate guide) gives you clean time-series: DGS2 for 2-year, DGS10 for 10-year, DGS30 for 30-year yields. The spread calculation is DGS10 - DGS2 — negative values mean inversion. Every US recession since 1970 has been preceded by a yield curve inversion, typically 12-18 months before the recession starts. This is not a market prediction; it is a mechanical consequence of the bond market repricing future growth expectations.

TIPS: Inflation Protection With Nuance

Treasury Inflation-Protected Securities (TIPS) adjust their principal based on CPI. If inflation runs at 3%, your TIPS principal increases by 3%, and the coupon (paid on the adjusted principal) increases proportionally. This sounds like a free lunch — protection against inflation with government backing.

The catch: TIPS have lower nominal yields than nominal Treasuries of the same maturity. The difference between the nominal Treasury yield and the TIPS yield is the "breakeven inflation rate" — the inflation rate at which the two bonds deliver equal returns. If actual inflation exceeds the breakeven, TIPS outperform. If it comes in below, nominal Treasuries win.

As of mid-2026, the 10-year breakeven rate hovers around 2.3%. This means the market expects roughly 2.3% annual inflation over the next decade. If you think inflation will average higher than that, TIPS are cheap. If you think the Fed will crush inflation below 2%, nominal bonds are the better bet. This is the kind of decision that replaces "should I buy bonds?" with an actual analytical framework.

Bond ETFs vs. Individual Bonds

Developer-investors gravitate toward ETFs because they trade like stocks and require zero bond-specific knowledge. A bond ETF like AGG or BND holds hundreds of bonds and maintains a roughly constant duration. This is convenient but introduces a behavior difference that matters: individual bonds have a known maturity date when you get your principal back. Bond ETFs never mature — they constantly sell bonds approaching maturity and buy new ones to maintain their target duration.

Consequence: if you buy a 5-year Treasury bond yielding 4%, you will get your principal back in 5 years regardless of what rates do in between. If you buy a bond ETF with 5-year average duration, a rate spike in year 4 will crush its price, and there is no guaranteed date when the price recovers. The ETF's duration stays constant; your individual bond's duration declines as it approaches maturity.

The practical advice: if you have a known future expense (tuition in 5 years, a house down payment in 3 years), buy individual bonds matched to the date. If you are managing a retirement portfolio with no specific withdrawal date, a low-cost bond ETF is simpler and adequately diversified.


Originally published at pickuma.com. Subscribe to the RSS or follow @pickuma.bsky.social for new reviews.

Top comments (0)