Eine Anleihe ist ein Strom von Versprechen
Eine Anleihe ist ein in handelbare Stücke zerlegter Kredit. Der Emittent verspricht in jeder Periode einen festen Kupon und bei Fälligkeit den Nennwert. Eine 10-jährige Anleihe mit Nennwert 1000 und 5 % Kupon, zweimal jährlich gezahlt, verspricht alle sechs Monate 25 und mit der letzten Zahlung zusätzlich 1000. Ihr Preis ist der heutige Wert dieser Versprechen: der Barwert der Zahlungen, abgezinst mit der Rendite, die der Markt derzeit für dieses Risiko und diese Laufzeit verlangt.
import numpy as np
def bond_cashflows(face, coupon_rate, years, freq):
n = int(round(years * freq)) # number of payments
times = np.arange(1, n + 1) / freq # in years: 0.5, 1.0, 1.5, ...
flows = np.full(n, face * coupon_rate / freq) # a coupon each time
flows[-1] += face # and the face value with the last one
return times, flows
times, flows = bond_cashflows(1000, 0.05, 2, 2) # a 2-year bond, to keep the output short
print(times.tolist()) # [0.5, 1.0, 1.5, 2.0]
print(flows.tolist()) # [25.0, 25.0, 25.0, 1025.0]Preis und Rendite bewegen sich gegenläufig
Zinsen Sie jede Zahlung mit (1 + ytm / freq) ** (freq * time) ab und addieren Sie. Entspricht die Rendite dem Kuponsatz, ist die Anleihe genau ihren Nennwert wert (sie notiert zu pari). Steigen die Marktrenditen über den Kupon, zahlen neue Anleihen mehr als diese, ihr Preis fällt also unter pari (ein Disagio); sinken sie, notiert sie mit Aufschlag. Es ist derselbe Mechanismus wie im vorigen Thema, nun mit echten Zahlungsterminen. Die laufende Rendite, Jahreskupon durch Preis, ist ein schnelles, aber unvollständiges Maß, weil sie Gewinn oder Verlust bei Fälligkeit ignoriert.
def bond_price(face, coupon_rate, ytm, years, freq=2):
times, flows = bond_cashflows(face, coupon_rate, years, freq)
return (flows / (1 + ytm / freq) ** (freq * times)).sum()
for ytm in (0.03, 0.05, 0.06, 0.08):
print(ytm, round(bond_price(1000, 0.05, ytm, 10), 2))
# 0.03 1171.69 yield below the coupon: premium
# 0.05 1000.0 yield = coupon: par
# 0.06 925.61 yield above the coupon: discount
# 0.08 796.15
print(round(50 / bond_price(1000, 0.05, 0.06, 10), 5)) # 0.05402 current yield: 5.40%, not the 6% yield to maturityLängere Anleihen reagieren stärker
Die relative Preisänderung bei einer gegebenen Renditebewegung hängt von der Laufzeit ab. Ferne Zahlungen werden mit einer hohen Potenz abgezinst und reagieren daher stark auf den Zins. Eine 1-jährige Anleihe verliert etwa 1 %, wenn die Renditen um einen Punkt steigen, eine 10-jährige etwa 7 %, eine 30-jährige fast 14 %. Deshalb sprechen Anleiheanleger vom Zinsänderungsrisiko, und deshalb entwickeln die nächsten Themen Maße (Rendite bis Fälligkeit, Duration), um es zu quantifizieren.
for years in (1, 5, 10, 30):
change = bond_price(1000, 0.05, 0.06, years) / 1000 - 1 # the coupon is 5%, the yield rises to 6%
print(years, round(change, 4))
# 1 -0.0096
# 5 -0.0427
# 10 -0.0744
# 30 -0.1384# The same 6% yield with annual, semiannual and monthly coupons: the quoting convention matters a little
for freq in (1, 2, 12):
print(freq, round(bond_price(1000, 0.05, 0.06, 10, freq), 2))
# 1 926.4
# 2 925.61
# 12 924.94freq). Echte Anleihen haben zudem Stückzinsen zwischen den Kupon-Terminen und Tageszählkonventionen, die dieses Lab ignoriert, indem es an Kuponterminen bewertet.- Preis = Summe aus
Zahlung / (1 + ytm / freq) ** (freq * Zeit); Kupons in jeder Periode, der Nennwert mit der letzten. - Rendite = Kuponsatz: Preis = pari; Rendite über dem Kupon: Disagio; darunter: Aufschlag. Preis und Rendite bewegen sich gegenläufig.
- Je länger die Laufzeit, desto größer die Preisänderung bei gleicher Renditebewegung: Dieses Zinsrisiko misst als Nächstes die Duration.
Als Nächstes: die Rendite bis Fälligkeit, in die andere Richtung: vom Marktpreis zurück zur Rendite.
Lab: Was bewertet wird
- Mit
bond_cashflowsdie Zahlungen einer Anleihe auflisten25 Pkt. - Mit
bond_pricedie Zahlungen zu einem Preis abzinsen25 Pkt. - Mit
current_yieldden Kupon mit dem Preis vergleichen25 Pkt. - Mit
price_changedie Wirkung einer Renditebewegung sehen25 Pkt.