σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft AcademySkills
Ctrl K
AO
+1,2 Tsd. Lernende
AnmeldenBeitreten ↗
Skills
AO
+1,2 Tsd. Lernende
Anmelden
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Python-Skill›Modul 4 · Bewertung von Anleihen und Optionen›Thema 4.15·~55 Min.Mittelstufe

Binomialbäume

Position in der SkillModul 4 von 11 · Thema 15 von 16
4.15 Binomialbäume
—Lab-Punkte— / 100XP gesamt—Serie—

Eine Aktie, die nur steigen oder fallen kann

Black-Scholes ist eine Formel, ein Binomialbaum ein Verfahren, und er kann bewerten, was die Formel nicht kann. Man zerlegt die Restlaufzeit in kleine Schritte. In jedem Schritt steigt die Aktie um den Faktor u oder fällt um den Faktor d, mehr nicht. Nach n Schritten gibt es n + 1 mögliche Preise. Die Auszahlungen sind bei Verfall bekannt, und jeder frühere Knoten ist der abgezinste Mittelwert der beiden Knoten, zu denen er führt; so füllt man den Baum rückwärts bis zur Gegenwart.

# One step: a stock at 100 goes to 110 or 90. What is a call with strike 100 worth?
import math

spot, strike, rate, dt = 100, 100, 0.05, 1.0
u, d = 1.10, 0.90
p = (math.exp(rate * dt) - d) / (u - d)             # the probability that makes the stock grow at the rate
up_value, down_value = max(spot * u - strike, 0), max(spot * d - strike, 0)
price = math.exp(-rate * dt) * (p * up_value + (1 - p) * down_value)
print(round(p, 4), round(up_value, 4), down_value)   # 0.7564 10.0 0
print(round(price, 4))                               # 7.1947

Die Wahrscheinlichkeit ist keine Prognose

Die Zahl p wird so gewählt, dass die Aktie im Mittel mit dem risikolosen Zins wächst: p * u + (1 - p) * d = exp(rate * dt), also p = (exp(rate * dt) - d) / (u - d). Das ist die risikoneutrale Wahrscheinlichkeit: ein Hilfsmittel, das ein Replikationsportfolio seinen abgezinsten Erwartungswert wert macht, keine Meinung darüber, wohin die Aktie läuft. Um die beobachtete Volatilität zu treffen, nutzt der Cox-Ross-Rubinstein-Baum (CRR) u = exp(sigma * sqrt(dt)) und d = 1 / u; ein Aufwärts- gefolgt von einem Abwärtsschritt führt zum selben Preis, der Baum rekombiniert: n Schritte ergeben nur n + 1 Endknoten.

# The CRR parameters and the prices at expiry of a 3-step tree
import math

def crr_parameters(rate, sigma, t, steps):
    dt = t / steps
    u = math.exp(sigma * math.sqrt(dt))
    d = 1 / u
    p = (math.exp(rate * dt) - d) / (u - d)
    return u, d, p

def terminal_prices(spot, u, d, steps):
    return [spot * u ** j * d ** (steps - j) for j in range(steps + 1)]

u, d, p = crr_parameters(0.05, 0.2, 1, 3)
print(round(u, 4), round(d, 4), round(p, 4))                     # 1.1224 0.8909 0.5438
print([round(price, 2) for price in terminal_prices(100, u, d, 3)])

Rückwärts rechnen

Bei Verfall ist jeder Knoten nur die Auszahlung, max(S - K, 0) für einen Call. Eine Spalte früher ist jeder Wert exp(-rate * dt) * (p * value_up + (1 - p) * value_down), und die Spalte verliert einen Knoten. Nach n Durchläufen bleibt ein einziger Wert, der heutige Preis. In Python ist eine Spalte eine Liste, ein Durchlauf eine List Comprehension über Nachbarpaare. Mit wachsender Schrittzahl konvergiert der Preis gegen den Black-Scholes-Preis, der Baum liefert, was die Formel sagt.

# The tree price of a European call approaches the Black-Scholes price as steps grow
import math

def norm_cdf(x):
    return 0.5 * (1 + math.erf(x / math.sqrt(2)))

def bs_call(spot, strike, rate, sigma, t):
    d1 = (math.log(spot / strike) + (rate + 0.5 * sigma ** 2) * t) / (sigma * math.sqrt(t))
    return spot * norm_cdf(d1) - strike * math.exp(-rate * t) * norm_cdf(d1 - sigma * math.sqrt(t))

def european_call_tree(spot, strike, rate, sigma, t, steps):
    dt = t / steps
    u = math.exp(sigma * math.sqrt(dt))
    d = 1 / u
    p = (math.exp(rate * dt) - d) / (u - d)
    disc = math.exp(-rate * dt)
    values = [max(spot * u ** j * d ** (steps - j) - strike, 0) for j in range(steps + 1)]
    for _ in range(steps):
        values = [disc * (p * values[j + 1] + (1 - p) * values[j]) for j in range(len(values) - 1)]
    return values[0]

print("Black-Scholes", round(bs_call(100, 100, 0.05, 0.2, 1), 4))
for steps in (1, 5, 25, 100, 400):
    print(steps, round(european_call_tree(100, 100, 0.05, 0.2, 1, steps), 4))

Vorzeitige Ausübung

Die eigentliche Stärke des Baums ist die Option, die die Formel nicht bewerten kann: Eine amerikanische Option kann jederzeit ausgeübt werden. An jedem Knoten vergleicht der Inhaber zwei Werte, den abgezinsten Erwartungswert des Haltens und die Auszahlung bei sofortiger Ausübung, und nimmt den größeren. Dieses eine zusätzliche max je Knoten ist die ganze Änderung des Algorithmus. Bei einem Call auf eine Aktie ohne Dividende lohnt vorzeitige Ausübung nie, bei einem Put kann sie sich lohnen: Ein tief im Geld liegender Put ist heute als Bargeld mehr wert, daher kostet der amerikanische Put mehr als der europäische.

# An American put against a European put: the early-exercise premium
import math

def tree(spot, strike, rate, sigma, t, steps, american):
    dt = t / steps
    u = math.exp(sigma * math.sqrt(dt))
    d = 1 / u
    p = (math.exp(rate * dt) - d) / (u - d)
    disc = math.exp(-rate * dt)
    values = [max(strike - spot * u ** j * d ** (steps - j), 0) for j in range(steps + 1)]
    for i in range(steps - 1, -1, -1):
        values = [disc * (p * values[j + 1] + (1 - p) * values[j]) for j in range(i + 1)]
        if american:
            values = [max(values[j], strike - spot * u ** j * d ** (i - j)) for j in range(i + 1)]
    return values[0]

for spot in (80, 100, 120):
    european = tree(spot, 100, 0.05, 0.2, 1, 200, False)
    american = tree(spot, 100, 0.05, 0.2, 1, 200, True)
    print(spot, round(european, 4), round(american, 4), "premium", round(american - european, 4))
Langsam und allgemein schlägt schnell und speziellFür einfache europäische Optionen ist die geschlossene Formel sofort und exakt, einen Baum würde man nie nehmen. Der Baum lohnt sich, wenn die Auszahlung eine Entscheidung (vorzeitige Ausübung), eine Barriere oder eine diskrete Dividende enthält: Man fügt die Regel an jedem Knoten hinzu. Der Preis ist Zeit: n Schritte kosten etwa n**2 / 2 Knotenaktualisierungen, und die Konvergenz ist nicht glatt (der Fehler schwankt, je nachdem wo der Strike zwischen den Knoten liegt); Bäume prüft man daher mit mehreren Schrittzahlen.
  • In jedem Schritt steigt die Aktie um u oder fällt um d; die CRR-Wahl u = exp(sigma * sqrt(dt)), d = 1 / u rekombiniert den Baum, n Schritte haben also n + 1 Endknoten.
  • Rückwärts bewerten: Auszahlungen bei Verfall, dann exp(-rate * dt) * (p * up + (1 - p) * down) je Knoten; p ist die risikoneutrale Wahrscheinlichkeit, keine Prognose.
  • Viele Schritte konvergieren gegen Black-Scholes; eine amerikanische Option fügt je Knoten ein max(Fortführung, Ausübung) hinzu, dafür gibt es Bäume.

Als Nächstes: Finite-Differenzen-Verfahren, bewerten, indem man die partielle Differentialgleichung der Option auf einem Gitter löst.

Lab: Was bewertet wird

  • Mit crr_parameters die Auf- und Abwärtsbewegung festlegen25 Pkt.
  • Mit terminal_prices die Preise bei Verfall auflisten25 Pkt.
  • Mit european_call_tree den Baum rückwärts durchlaufen25 Pkt.
  • Mit american_put_tree vorzeitige Ausübung erlauben25 Pkt.
Explorer · lab-80-1
▾ lab-80-1
…
bash · im Browser
learner@quantcraft:~/lab-80-1$
Python noch nicht geladenPythonLn 1, Col 1Spaces: 4UTF-8

Dieses Thema zurücksetzen?

Alles in lab-80-1 wird auf die Startdateien zurückgesetzt und das Terminal geleert. Ihre aktuelle Lösung geht verloren – das lässt sich nicht rückgängig machen.

Wird zurückgesetzt
  • main.py → Startcode
  • Terminal-Verlauf und Testausgabe
  • Nicht eingereichte Änderungen
Bleibt erhalten
  • Beste Lab-Punktzahl
  • Ihre XP und Ihre Serie
  • Vorlesungsfortschritt und Notizen

Melde dich an, um deinen Code auszuführen.

Alle Lektionen kannst du kostenlos lesen. Erstelle ein Konto oder melde dich an, um Code auszuführen, Tests zu starten und dieses Lab abzugeben.

  • IDE im Browser mit Bash-Terminal — nichts zu installieren
  • Sofortige Bewertung, XP und dein Platz auf der Skill
Konto erstellenAnmelden
ODER
Weiter mit GitHub