Rendite und Risiko in einer Zahl
Minimale Varianz ignoriert Renditen. Die Mittelwert-Varianz-Optimierung (Markowitz) nutzt beides: Ein Anleger will eine hohe erwartete Rendite w @ mu und eine niedrige Varianz w @ cov @ w. Ein einfacher Kompromiss ist der Nutzen w @ mu - 0.5 * lambda * w @ cov @ w, wobei lambda die Risikoaversion ist: Je höher, desto mehr kostet eine Varianzeinheit. Zwei Anleger mit gleichen Erwartungen, aber verschiedenem lambda wählen verschiedene Portfolios, und das beste Portfolio jedes Anlegers ist das Maximum einer glatten, konkaven Funktion.
import numpy as np
mu = np.array([0.08, 0.05, 0.10]) # expected annual returns
cov = np.array([[0.0400, 0.0060, 0.0100],
[0.0060, 0.0100, 0.0020],
[0.0100, 0.0020, 0.0225]])
def utility(weights, mu, cov, risk_aversion):
return weights @ mu - 0.5 * risk_aversion * weights @ cov @ weights
equal = np.full(3, 1 / 3)
print(round(float(equal @ mu), 4), round(float(equal @ cov @ equal), 4)) # 0.0767 0.0121
print(round(float(utility(equal, mu, cov, 4.0)), 4)) # 0.0526Die beste Position bei gegebener Risikoaversion
Ohne Budgetrestriktion (das übrige Geld verdient den risikolosen Zins, hier als null in Überrenditen genommen) liegt die beste Position dort, wo der Gradient mu - lambda * cov @ w null ist: w = cov^-1 * mu / lambda. Im Code np.linalg.solve(cov, mu) / lambda. Es skaliert, wie der gesunde Menschenverstand sagt: doppelte Risikoaversion, halbe Position. Die Summe der Gewichte ist, was sie sein muss; der Rest, 1 - w.sum(), ist Bargeld.
# The best position for several risk aversions: more aversion, smaller bets
import numpy as np
mu = np.array([0.08, 0.05, 0.10])
cov = np.array([[0.0400, 0.0060, 0.0100],
[0.0060, 0.0100, 0.0020],
[0.0100, 0.0020, 0.0225]])
for aversion in (5.0, 10.0, 20.0):
w = np.linalg.solve(cov, mu) / aversion
print(aversion, np.round(w, 3), "invested", round(float(w.sum()), 3))Das Tangentialportfolio
Mit einem risikolosen Asset halten alle Anleger dieselbe riskante Mischung, nur in unterschiedlicher Menge. Diese Mischung hat die höchste Sharpe-Ratio (w @ mu - rf) / sqrt(w @ cov @ w), das Tangentialportfolio: w proportional zu cov^-1 * (mu - rf), auf Summe 1 skaliert. Der vorsichtige Anleger legt nur einen Teil des Geldes darin an und den Rest in bar; der mutige leiht sich Geld, um mehr zu halten. Wie viel Risiko man eingeht und welche riskanten Assets man hält, sind zwei getrennte Probleme.
# The tangency portfolio: no other mix of the three assets has a higher Sharpe ratio
import numpy as np
mu = np.array([0.08, 0.05, 0.10])
cov = np.array([[0.0400, 0.0060, 0.0100],
[0.0060, 0.0100, 0.0020],
[0.0100, 0.0020, 0.0225]])
rf = 0.02
x = np.linalg.solve(cov, mu - rf)
best = x / x.sum()
def sharpe(w):
return (w @ mu - rf) / np.sqrt(w @ cov @ w)
rng = np.random.default_rng(1)
trials = rng.normal(size=(2000, 3))
trials = trials / trials.sum(axis=1, keepdims=True)
print(np.round(best, 4), round(float(sharpe(best)), 4))
print(round(max(float(sharpe(w)) for w in trials), 4)) # the best of 2000 random mixes comes close, never aboveEin Renditeziel erreichen
Eine andere Fragestellung: Welches unter allen Portfolios mit Summe 1 und gegebener erwarteter Rendite hat die kleinste Varianz? Mit zwei Nebenbedingungen ist die Lösung eine Kombination der beiden gelösten Vektoren s1 = cov^-1 * 1 und sm = cov^-1 * mu, mit Koeffizienten aus vier Zahlen a, b, c, d, die den Markt zusammenfassen. Jede Zielrendite liefert ein Portfolio; das Risiko aller aufzutragen ergibt die Effizienzlinie des nächsten Themas.
# Minimum-variance portfolios for three target returns
import numpy as np
mu = np.array([0.08, 0.05, 0.10])
cov = np.array([[0.0400, 0.0060, 0.0100],
[0.0060, 0.0100, 0.0020],
[0.0100, 0.0020, 0.0225]])
ones = np.ones(3)
s1, sm = np.linalg.solve(cov, ones), np.linalg.solve(cov, mu)
a, b, c = ones @ s1, ones @ sm, mu @ sm
d = a * c - b ** 2
for target in (0.06, 0.08, 0.09):
w = ((c - b * target) * s1 + (a * target - b) * sm) / d
print(target, np.round(w, 3), round(float(w @ mu), 4), round(float(np.sqrt(w @ cov @ w)), 4))mu: Eine kleine Änderung einer erwarteten Rendite kann das Portfolio von einem Asset zu einem anderen schwenken. Der Optimierer vertraut den Eingaben vollständig, jede überschätzte Rendite wird also zu einer großen Position. In der Praxis werden Renditen geschrumpft, Gewichte begrenzt, und die Eingaben stammen aus Modellen oder Einschätzungen statt aus rohen Vergangenheitsmitteln. Mittelwert-Varianz ist ein gutes Denkwerkzeug und blind angewendet ein gefährliches.- Der Nutzen ist
w @ mu - 0.5 * lambda * w @ cov @ w; die beste Position ohne Budget istsolve(cov, mu) / lambda, und doppelteslambdahalbiert sie. - Mit einem risikolosen Asset ist die beste riskante Mischung das Tangentialportfolio
solve(cov, mu - rf), auf Summe 1 skaliert: die höchste Sharpe-Ratio. - Für eine Zielrendite sind die Minimum-Varianz-Gewichte eine Kombination aus
solve(cov, ones)undsolve(cov, mu); das Ergebnis ist nur so gut wie das geschätztemu.
Als Nächstes: die Effizienzlinie, die Kurve des besten Risikos für jedes Renditeniveau.
Lab: Was bewertet wird
- Ein Portfolio mit
utilitybewerten25 Pkt. - Mit
utility_weightsdie beste Position finden25 Pkt. - Mit
tangency_weightsdie Sharpe-Ratio maximieren25 Pkt. - Mit
target_return_weightsein Renditeziel erreichen25 Pkt.