Optionen mit Falltür
Eine Barrier-Option ist ein Call oder Put mit einem Schalter. Eine Knock-out-Option erlischt, wenn der Preis die Barriere berührt; eine Knock-in-Option entsteht nur dann. Die Barriere kann über dem Start (up) oder darunter (down) liegen. Da der Käufer auf einen Teil der Auszahlung verzichtet, sind Barrier-Optionen billiger als einfache, deshalb sind sie beliebt, auch in strukturierten Produkten. Wie asiatische Optionen hängen sie vom ganzen Pfad ab, das natürliche Werkzeug ist die Simulation.
import numpy as np
paths = np.array([[100.0, 105.0, 112.0, 108.0], # stays below 115
[100.0, 98.0, 103.0, 110.0], # stays below 115
[100.0, 120.0, 95.0, 90.0]]) # touches 115 on day 1, then falls
hit_up = paths.max(axis=1) >= 115.0 # the maximum of each path against the barrier
print(hit_up) # [False False True]
print(paths.min(axis=1) <= 96.0) # a down barrier at 96: [False False True]# hit_barrier for both directions, with an error for anything else
import numpy as np
def hit_barrier(paths, barrier, direction):
if direction == "up":
return paths.max(axis=1) >= barrier
if direction == "down":
return paths.min(axis=1) <= barrier
raise ValueError("direction must be 'up' or 'down'")
paths = np.array([[100.0, 110.0, 105.0], [100.0, 109.9, 105.0]])
print(hit_barrier(paths, 110.0, "up")) # [ True False]: touching the barrier exactly counts
try:
hit_barrier(paths, 110.0, "sideways")
except ValueError as error:
print("rejected:", error)Knock-out, Knock-in und die Summe
Berechnen Sie auf jedem Pfad die Auszahlung des einfachen Calls max(S_T - K, 0) und das Barrier-Flag. Der Knock-out-Call behält die Auszahlung dort, wo die Barriere *nicht* berührt wurde; der Knock-in-Call dort, wo sie berührt wurde. Jeder Pfad ist das eine oder das andere, also *In + Out = einfacher Call*, Pfad für Pfad, eine praktische Identität: Bewerten Sie die einfachere und erhalten Sie die andere gratis, und nutzen Sie sie als Test Ihres Codes. np.where(hit, a, b) wählt elementweise zwischen Arrays.
import numpy as np
paths = np.array([[100.0, 105.0, 112.0, 108.0],
[100.0, 98.0, 103.0, 110.0],
[100.0, 120.0, 95.0, 130.0]])
strike, barrier = 100.0, 115.0
vanilla = np.maximum(paths[:, -1] - strike, 0.0)
hit = paths.max(axis=1) >= barrier
knock_out = np.where(hit, 0.0, vanilla)
knock_in = np.where(hit, vanilla, 0.0)
print(vanilla, knock_out, knock_in) # [ 8. 10. 30.] [ 8. 10. 0.] [ 0. 0. 30.]
print(np.allclose(knock_in + knock_out, vanilla)) # TrueBewertung und der Bias der diskreten Beobachtung
Der Preis ist die abgezinste mittlere Auszahlung wie zuvor. Doch Vorsicht bei der Barrierenprüfung: Eine Simulation betrachtet den Preis nur an ihren Gitterterminen, während eine echte kontinuierliche Barriere auch *zwischen* ihnen durchbrochen wird. Bei wenigen Schritten überqueren simulierte Pfade die Barriere oft unbemerkt, ein Knock-out-Call wird zu teuer und ein Knock-in zu billig. Mehr Schritte verringern den Bias, ebenso Korrekturen, die die Barriere um etwa 0.5826 * sigma * sqrt(dt) verschieben.
import numpy as np
def simulate_paths(s0, rate, sigma, t, steps, n_paths, rng):
dt = t / steps
z = rng.standard_normal((n_paths, steps))
moves = (rate - 0.5 * sigma ** 2) * dt + sigma * np.sqrt(dt) * z
return s0 * np.exp(np.hstack([np.zeros((n_paths, 1)), np.cumsum(moves, axis=1)]))
def knock_out_price(paths, strike, barrier, rate, t):
vanilla = np.maximum(paths[:, -1] - strike, 0.0)
payoff = np.where(paths.max(axis=1) >= barrier, 0.0, vanilla)
return float(np.exp(-rate * t) * payoff.mean())
rng = np.random.default_rng(1)
for steps in (12, 52, 252):
paths = simulate_paths(100.0, 0.05, 0.25, 1.0, steps, 40000, rng)
print(steps, round(knock_out_price(paths, 100.0, 130.0, 0.05, 1.0), 3)) # the price falls as monitoring gets finer- Eine Barriere wird berührt, wenn das Maximum (up) oder Minimum (down) des Pfads sie an irgendeinem Termin erreicht; Knock-out stirbt bei Berührung, Knock-in entsteht bei Berührung.
- Pro Pfad gilt Knock-in + Knock-out = Auszahlung des einfachen Calls;
np.where(hit, a, b)wählt aus; Barrier-Optionen sind billiger als einfache. - Simulation auf einem Gitter verpasst Überschreitungen zwischen den Terminen, Knock-outs wirken zu teuer: mehr Schritte nutzen oder die Barriere verschieben; Vorsicht vor Gap-Risiko nahe der Barriere.
Als Nächstes: antithetische Variablen, eine Möglichkeit, dieselbe Monte-Carlo-Genauigkeit mit weniger Simulationen zu erreichen.
Lab: Was bewertet wird
- Mit
hit_barrierdie Berührung erkennen25 Pkt. - Mit
knock_out_call_payoffdie Option beenden25 Pkt. - Mit
knock_in_call_payoffzum Leben erwecken25 Pkt. - Mit
barrier_priceAuszahlungen in einen Preis verwandeln25 Pkt.