σμ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 AcademyParcours
Ctrl K
AO
+1,2 k apprenants
ConnexionRejoindre ↗
Parcours
AO
+1,2 k apprenants
Connexion
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Parcours Python›Module 8 · Modèles stochastiques et apprentissage automatique›Sujet 8.4·~55 minAvancé

Options asiatiques

Position dans le parcoursModule 8 sur 11 · Sujet 4 sur 10
8.4 Options asiatiques
—Score du lab— / 100XP total—Série—

Payer sur la moyenne

Un call standard dépend du prix un seul jour, le dernier. Une option asiatique dépend du prix moyen sur un ensemble de dates : un call asiatique paie max(moyenne - K, 0). Les entreprises les utilisent pour couvrir un coût qu'elles supportent régulièrement, par exemple un achat mensuel de pétrole, et elles sont difficiles à manipuler à l'échéance. Elles *dépendent de la trajectoire*, donc il n'existe pas de formule de Black–Scholes simple pour la moyenne arithmétique, et l'outil habituel est la simulation de Monte Carlo.

import numpy as np

# Two simulated paths: the starting price, then monthly prices; the last column is expiry
paths = np.array([[100.0, 90.0, 110.0, 130.0],
                  [100.0, 70.0,  80.0,  90.0]])
average = paths[:, 1:].mean(axis=1)                      # the monitoring dates only, not the starting price
print(average)                                           # [110.  80.]
print(np.maximum(average - 100.0, 0.0))                  # Asian call payoffs: [10.  0.]
print(np.maximum(paths[:, -1] - 100.0, 0.0))             # European call payoffs on the same paths: [30.  0.]

Simuler les trajectoires

Les trajectoires viennent du mouvement brownien géométrique, avec la dérive risque-neutre : le taux r remplace mu. On tire une matrice de lois normales centrées réduites, une ligne par trajectoire et une colonne par date de suivi, on la transforme en variations du log du prix, et on fait une somme cumulée le long de chaque ligne. Un seul tableau contient alors toutes les trajectoires, et chaque étape suivante (moyennes, gains) est une opération vectorisée le long des lignes, sans boucle sur les trajectoires.

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))
    log_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(log_moves, axis=1)]))

rng = np.random.default_rng(1)
paths = simulate_paths(100.0, 0.05, 0.2, 1.0, 12, 50000, rng)       # monthly monitoring for a year
print(paths.shape)                                                   # (50000, 13)
print(round(float(paths[:, -1].mean()), 2), round(100 * np.exp(0.05), 2))      # the risk-neutral mean of the final price

Le prix et sa barre d'erreur

Le prix de l'option est le gain moyen actualisé : exp(-r * T) * mean(payoffs). Un prix Monte Carlo est une estimation, donc rapportez toujours son erreur standard, std(payoffs) / sqrt(nombre de trajectoires) (actualisée), qui indique de combien le nombre peut s'écarter de la vérité : quatre fois plus de trajectoires la divisent par deux. Un call asiatique est moins cher qu'un call européen sur la même action, car la moyenne lisse le prix et abaisse la volatilité effective.

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))
    log_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(log_moves, axis=1)]))

def asian_price(paths, strike, rate, t):
    payoff = np.maximum(paths[:, 1:].mean(axis=1) - strike, 0.0)
    discount = np.exp(-rate * t)
    return discount * payoff.mean(), discount * payoff.std(ddof=1) / np.sqrt(len(payoff))

rng = np.random.default_rng(1)
paths = simulate_paths(100.0, 0.05, 0.2, 1.0, 12, 100000, rng)
price, error = asian_price(paths, 100.0, 0.05, 1.0)
european = np.exp(-0.05) * np.maximum(paths[:, -1] - 100.0, 0.0).mean()
print(round(float(price), 3), "+/-", round(float(error), 3))
print(round(float(european), 3), "European call on the same paths")
# Geometric and arithmetic averages of the same monitoring prices
import numpy as np

prices = np.array([90.0, 110.0, 130.0])
arithmetic = prices.mean()
geometric = np.exp(np.log(prices).mean())
print(round(float(arithmetic), 3), round(float(geometric), 3))        # 110.0 108.774: the geometric average is never larger
La moyenne géométrique a une formuleUn produit de lois log-normales est log-normal, donc une option asiatique sur la moyenne géométrique peut être valorisée par une formule de type Black–Scholes. Cela en fait un bon contrôle et, plus encore, une variable de contrôle pour l'arithmétique : les deux gains sont très corrélés, donc le prix exact connu de l'option géométrique peut annuler une grande part du bruit Monte Carlo. Un sujet ultérieur, les variables de contrôle, utilise exactement cette idée.
  • Une option asiatique paie sur la moyenne des dates de suivi : max(moyenne - K, 0) ; elle dépend de la trajectoire, donc pas de formule simple et Monte Carlo est l'outil.
  • Simulez toutes les trajectoires dans un seul tableau (lignes = trajectoires, colonnes = dates) avec la dérive risque-neutre ; moyennes et gains sont alors vectorisés par lignes.
  • Prix = exp(-r * T) * mean(payoffs) avec une erreur standard std / sqrt(paths) ; la moyenne le rend moins cher qu'un call européen, et la version géométrique est une variable de contrôle.

À suivre : les options à barrière, qui naissent ou meurent quand le prix touche un niveau.

Lab : ce qui est noté

  • Moyenner le long de chaque trajectoire avec average_price25 pts
  • Essayer la moyenne géométrique avec geometric_average25 pts
  • Payer sur la moyenne avec asian_call_payoff25 pts
  • La valoriser, avec une barre d'erreur, avec asian_price25 pts
Explorateur · lab-105-1
▾ lab-105-1
…
bash · dans le navigateur
learner@quantcraft:~/lab-105-1$
Python pas encore chargéPythonLn 1, Col 1Spaces: 4UTF-8

Réinitialiser ce sujet ?

Tout le contenu de lab-105-1 revient aux fichiers de départ et le terminal est vidé. Votre solution actuelle sera perdue : cette action est irréversible.

Sera réinitialisé
  • main.py → code de départ
  • Historique du terminal et sortie des tests
  • Modifications non soumises
Sera conservé
  • Meilleur score du lab
  • Votre XP et votre série
  • Progression du cours et notes

Connectez-vous pour exécuter votre code.

Tous les cours sont gratuits à lire. Créez un compte ou connectez-vous pour exécuter du code, lancer les tests et soumettre ce lab.

  • IDE dans le navigateur avec terminal bash — rien à installer
  • Correction instantanée, XP et votre place dans le parcours
Créer un compteSe connecter
OU
Continuer avec GitHub