Vom Preis zurück zur Rendite
Am Markt wird eine Anleihe über den Preis notiert, doch Anleger vergleichen Anleihen über die Rendite. Die Rendite bis Fälligkeit (YTM) ist der eine Diskontsatz, bei dem der Barwert aller Zahlungen der Anleihe ihrem Preis entspricht: die annualisierte Rendite, die Sie erzielen, wenn Sie jetzt kaufen, bis Fälligkeit halten und alle Zahlungen geleistet werden. Bei einer 10-jährigen Anleihe zu 925,61 mit 5 % Kupon sind es 6 %. Anders als der Preis hat die YTM keine geschlossene Formel, weil die Unbekannte in einem Polynom hohen Grades steckt.
import numpy as np
def bond_price(face, coupon_rate, ytm, years, freq=2):
n = int(round(years * freq))
times = np.arange(1, n + 1) / freq
flows = np.full(n, face * coupon_rate / freq)
flows[-1] += face
return (flows / (1 + ytm / freq) ** (freq * times)).sum()
price = bond_price(1000, 0.05, 0.06, 10)
print(round(price, 4)) # 925.6126 the market price we pretend to observe
# A back-of-the-envelope yield: annual coupon plus the yearly share of the discount, over the average of price and par
coupon = 1000 * 0.05
print(round((coupon + (1000 - price) / 10) / ((1000 + price) / 2), 5)) # 0.05966 close to 6%, but not exactSuchen: Bisektion
Der Preis fällt stetig, wenn die Rendite steigt, man kann also suchen. Nehmen Sie ein Intervall [low, high], das die Antwort sicher enthält (0 % bis 100 %). Bewerten Sie die Anleihe in der Mitte: Liegt der Preis über dem Ziel, muss die Rendite höher sein, also setzen Sie low auf die Mitte; sonst senken Sie high. Jeder Schritt halbiert das Intervall, 40 Schritte verkleinern es um den Faktor einer Billion. Bisektion ist im Vergleich mit anderen Verfahren langsam, kann aber nicht scheitern, solange die Antwort im Intervall liegt, und ist damit der sichere Rückgriff.
low, high = 0.0, 1.0
for step in range(6):
mid = (low + high) / 2
price_mid = bond_price(1000, 0.05, mid, 10)
print(step, round(mid, 5), round(price_mid, 2))
if price_mid > price: # priced too high: the yield must be higher
low = mid
else:
high = mid
# 0 0.5 110.38
# 1 0.25 275.86
# 2 0.125 578.47
# 3 0.0625 908.08
# 4 0.03125 1159.97
# 5 0.04688 1024.72 the interval keeps shrinking around 6% (the target price is 925.61)Schneller suchen: Newton
Das Newton-Verfahren nutzt die Steigung. Setzen Sie f(y) = bond_price(y) - Ziel; gesucht ist f(y) = 0. Folgen Sie an der aktuellen Schätzung der Tangente bis null: y_new = y - f(y) / f'(y). Die Steigung lässt sich numerisch mit einem winzigen Schritt h schätzen: (f(y + h) - f(y - h)) / (2h). Nahe der Lösung verdoppelt sich die Zahl richtiger Stellen etwa mit jedem Schritt, vier oder fünf Schritte genügen also, wo die Bisektion vierzig braucht. Newton kann bei schlechtem Start oder flacher Steigung scheitern; behalten Sie daher ein Schrittlimit und greifen Sie auf die Bisektion zurück, falls es nicht konvergiert.
y, h = 0.05, 1e-6 # start at the coupon rate
for step in range(5):
f = bond_price(1000, 0.05, y) - price
slope = (bond_price(1000, 0.05, y + h) - bond_price(1000, 0.05, y - h)) / (2 * h)
print(step, round(y, 8), round(f, 6))
y = y - f / slope
# 0 0.05 74.387374
# 1 0.05954347 3.245932
# 2 0.05999903 0.006916
# 3 0.06 0.0
# 4 0.06 0.0 converged to 6% after 3 steps# Check the answer by pricing the bond at the yield we found
print(round(bond_price(1000, 0.05, y, 10), 4), round(price, 4)) # 925.6126 925.6126 the same price: the yield is right- Die YTM ist der Diskontsatz, bei dem der Barwert der Anleihe ihrem Preis entspricht; sie hat keine geschlossene Formel und wird gesucht.
- Bisektion:
[low, high]immer weiter halbieren (Preis über Ziel:lowanheben); langsam, aber sicher. - Newton:
y = y - f / slopemit numerischer Steigung; es konvergiert in wenigen Schritten, braucht aber ein Schrittlimit und einen guten Start.
Als Nächstes: Duration und Konvexität, die Sensitivität des Anleihepreises gegenüber der Rendite messen.
Lab: Was bewertet wird
- Mit
approx_ytmdie Rendite überschlagen25 Pkt. - Mit
bisect_yielddie Rendite durch Halbieren des Intervalls finden25 Pkt. - Mit
newton_yielddie Rendite schneller finden25 Pkt. - Mit
classify_pricedie Lage der Anleihe benennen25 Pkt.