Vous êtes sur la page 1sur 13

Compte Rendu TP EDP Options Américaines Yahya Bajdadi

November 21, 2023

1 Compte Rendu
1.1 Tache 1: GSP
[76]: import numpy.linalg as la
import numpy as np
import matplotlib.pyplot as plt
from math import exp, log
import math

def mult(A, B, start, end, numlignes):


return np.sum(A[numlignes, start:end]* B[start:end])

def calc(A, X, B, G, N):


Z = np.zeros(N)
for n in range(N):
val_y = (1/A[n][n])*(B[n] - mult(A,Z,1,n,n)- mult(A,X,n+1,N+1,n))
Z[n] = max(val_y, G[n])
return Z

def norme(X):
return la.norm(X)

def GSP(A,N,B,G, X_0, epsilon=0.0001, K_max=1000):

X_old, X_new = X_0, X_0


X_new = calc(A, X_old, B, G, N)
k=1
while norme(X_new-X_old)/norme(X_old) > epsilon and k<K_max:
X_old =X_new
X_new = calc(A, X_old, B, G, N)
k +=1
return X_new, k

1
1.1.1 Commentaires:
On a implémenté la routine de GaussSeidel sachant que celle ci était bien définie grâce au cours.
Dans ce qui suit on essaiera d’utiliser cette méthode à un problème de corde/obstacle avant de
l’appliquer au calcule du prix d’une Option américaine par changement de variable et résolution
d’une EDP.
[77]: def g(x):
val1 = 3*exp(-((x+0.4)**2)/0.1)
val2 = 4*exp(-((x-0.4)**2)/0.2)
return val1 + val2 -1

def construct_A(alpha, beta, gamma, N):


A = np.zeros((N,N))
diag = np.array([alpha for _ in range(N)])
np.fill_diagonal(A, diag)
surdiag = np.array([beta for _ in range(N-1)])
sousdiag = np.array([gamma for _ in range(N-1)])

np.fill_diagonal(A[0:-1, 1:], surdiag)


np.fill_diagonal(A[1:, 0:-1], sousdiag)
return A

def phi(x, K, option_type):


if option_type == 'call':
return np.maximum(x - K, 0)
elif option_type == 'put':
return np.maximum(K - x, 0)

def gamma_func( dx, dt, r, sigma, delta):


val1 = -(sigma**2)*dt/(2*dx**2)
val2 = (r-delta-(sigma**2)/(2*dx))
return val1 + val2

def beta_func( dx, dt, r, sigma, delta):


val1 = -(sigma ** 2) * dt / (2 * dx ** 2)
val2 = (r - delta - (sigma ** 2) / (2 * dx))
return val1 - val2

def alpha_func(dx, dt, r, sigma):


val1 = (sigma ** 2) * dt / (dx ** 2)
val2 = 1 + r*dt
return val1 + val2

2
1.2 Tache 2: Problème d’obstacle
On utilise désormais les méthodes ci-dessus pour résoudre le problème grâce à une fonction g donnée
par le sujet dans un premier temps, avant de l’eesayer sur une autre fonciton differente.
[78]: def test_GSP(N):

alpha = 2
beta = -1
gamma =-1

a = -1
b = 1

A = construct_A(alpha, beta, gamma, N)

dx = (b-a) / (N+1)

grille = [-1 +i*dx for i in range(N+2)]

B = np.zeros(N)
G = np.array([g(grille[k]) for k in range(1, N+1)])
X_0 = np.array([2 for _ in range(N)])

X, k = GSP(A, N, B, G, X_0)

zero_deb = np.array([0])
zero_fin = np.array([0])

X_elargie = np.concatenate((zero_deb, X, zero_fin))

g_vals = [g(x) for x in grille]

title = f"Avec un nombre d'iterations = {k}"


plt.plot(grille, g_vals)
plt.plot(grille, X_elargie)
plt.title(title)
plt.grid(True)
plt.show()

[79]: test_GSP(100)

3
[80]: test_GSP(500)

4
[81]: test_GSP(1000)

1.2.1 Commentaire:
On remarque que la solution ne colle pas parfaitement surtout aux alentours des bords. Ceci s’ajoute
au fait que pour différents N, on remarque que le nombre d’itérations nécessaires pour calculer le
X k stage à partir d’un certain moment à cause de la limitation du nombre d’itérations imposé sur
la fonction GSP ainsi que le rapprochement de Xk+1 et Xk qui pourrait arrêter la boucle dès que
la différence entre deux pas soit assez (mais pas suffisament) petite. Ceci entraîne des anomalies
sur la solution du problème qu’on purrait remarquer également sur la fonction “obstacle” suivante:
[82]: def g_autre(t, sigma, p, b, a, x):

val1 = math.exp(-(t*(sigma**2)/2)*((p*math.pi/(b-a))**2))
val2 = math.sin((math.pi*p*(x-a))/(b-a))
return val1*val2

def test_GSP_g_autre(N):

alpha = 2
beta = -1
gamma =-1

sigma = 0.2
p = 10

5
t = 0

a = -1
b = 1

A = construct_A(alpha, beta, gamma, N)

dx = (b-a) / (N+1)

grille = [-1 +i*dx for i in range(N+2)]

B = np.zeros(N)
G = np.array([g_autre(t, sigma, p, b, a,grille[k]) for k in range(1, N+1)])
X_0 = np.array([2 for _ in range(N)])

X, k = GSP(A, N, B, G, X_0)

zero_deb = np.array([0])
zero_fin = np.array([0])

X_elargie = np.concatenate((zero_deb, X, zero_fin))

g_vals = [g_autre(t, sigma, p, b, a,x) for x in grille]

title = f"Avec un nombre d'iterations = {k}"


plt.plot(grille, g_vals)
plt.plot(grille, X_elargie)
plt.title(title)
plt.grid(True)
plt.show()

[83]: test_GSP_g_autre(100)

6
[84]: test_GSP_g_autre(500)

7
1.2.2 Commentaires:
On remarque ainsi que les iterations restent bloquer par le nombre prédefini et donc notre solution
n’arrive pas à converger.
On remarque également que la condition de contact n’est ainsi pas satisfaite à cause de la divergence
des solutions.

1.3 Tache 3: Option Américaine


Dans cette partie on essayera de calculer le prix d’une option Américaine grâce à la méthode vu
précedement, et essayerons de tracer ses zones de contact dans le cas d’un Call puis d’un Put.
[85]: def main_call(r, delta):
N = 100
M = 100
K = 1
T = 1
sigma = 0.5
a = log(K / 10)
b = log(K * 10)
dx = (b - a) / (N + 1)
dT = T / M
# result = option_americaine(T, N, M, a, b, K, r, sigma, delta)
#
# print(result)
x = np.linspace(a, b, N + 2)
U = np.zeros((N + 2, M + 1))
U[:, 0] = phi(np.exp(x), K, 'call') # Initialisation de U avec phi(exp(x))

# Calcul des coefficients pour la résolution


alpha = 1 + ((sigma ** 2 * dT) / (2 * dx ** 2)) + r * dT
beta = -((sigma ** 2 * dT) / (4 * dx ** 2)) - (r * dT / 2)
gamma = ((sigma ** 2 * dT) / (4 * dx ** 2)) - (r * dT / 2)

A = np.diag(alpha * np.ones(N)) + np.diag(beta * np.ones(N - 1), 1) + np.


,→ diag(gamma * np.ones(N - 1), -1)

F = np.zeros(N)
F[0] = -gamma * phi(np.exp(a), K, 'call')
F[N - 1] = -beta * phi(np.exp(b), K, 'call')

# Résolution du problème itérativement


for m in range(M):

B = U[1:N + 1, m] + F

result, _ = GSP(A, N, B, U[1:N + 1, m], U[1:N + 1, m], 0.0001, 1000)


U[1:N + 1, m + 1] = result

8
NewU = U[::-1]
C = np.zeros((N + 2, M + 1))
for m in range(M + 1):
for n in range(N + 2):
if NewU[n, m] == 0 :
if r>0:
C[n, m] = 1
else:
C[n, m] = 0
grilleTmp2 = [T - (M - i) * dT for i in range(M + 1)]

pasSp = (K / 10) * dx

grilleSp2 = [(K / 10) + (K * (9.9) / N) * i for i in range(N + 2)]

plt.imshow( np.transpose(C), interpolation = 'nearest', cmap='bwr')


plt.colorbar()
plt.grid()
plt.show()

[86]: main_call(0.02, 0.01)

On remarque que la zone de contacte du Call Américain correspond à celle vu en cours à une
transposition près vu que dans notre graphe l’axxe horizontrale est celui du temps et le vertical
correspond aux valeurs des actifs.

9
[87]: def main_put():
N = 100
M = 100
K = 1
T = 1
sigma = 0.5
r = 0.02
delta = 0
a = log(K / 10)
b = log(K * 10)
dx = (b - a) / (N + 1)
dT = T / M
# result = option_americaine(T, N, M, a, b, K, r, sigma, delta)
#
# print(result)
x = np.linspace(a, b, N + 2)
U = np.zeros((N + 2, M + 1))
U[:, 0] = phi(np.exp(x), K, 'call') # Initialisation de U avec phi(exp(x))

# Calcul des coefficients pour la résolution


alpha = 1 + ((sigma ** 2 * dT) / (2 * dx ** 2)) + r * dT
beta = -((sigma ** 2 * dT) / (4 * dx ** 2)) - (r * dT / 2)
gamma = ((sigma ** 2 * dT) / (4 * dx ** 2)) - (r * dT / 2)

A = np.diag(alpha * np.ones(N)) + np.diag(beta * np.ones(N - 1), 1) + np.


diag(gamma * np.ones(N - 1), -1)
,→

F = np.zeros(N)
F[0] = -gamma * phi(np.exp(a), K, 'call')
F[N - 1] = -beta * phi(np.exp(b), K, 'call')

# Résolution du problème itérativement


for m in range(M):

B = U[1:N + 1, m] + F

result, _ = GSP(A, N, B, U[1:N + 1, m], U[1:N + 1, m], 0.0001, 1000)


U[1:N + 1, m + 1] = result

NewU = U[::-1]
C = np.zeros((N + 2, M + 1))
for m in range(M + 1):
for n in range(N + 2):
if NewU[n, m] == 0 :
C[n, m] = 1
grilleTmp2 = [T - (M - i) * dT for i in range(M + 1)]

10
pasSp = (K / 10) * dx

grilleSp2 = [(K / 10) + (K * (9.9) / N) * i for i in range(N + 2)]

NewC = C[:, ::-1]

plt.imshow( np.transpose(NewC), interpolation = 'nearest', cmap='bwr')


plt.colorbar()
plt.grid()
plt.show()

[88]: main_put()

On remarque la même chose dans le cas du Put Américain que le Call en terme de correspondance
entre ce résultat graphique et celui retrouvé durant le cours.
Durant notre parcours pour appliquer GSP, on a choisit d’utiliser la dernière valeur calculée Um
pour le X_0 de GSP pour avoir l’évolution du prix de notre option au cours du temps et ainsi
pouvoir effectuer une analyse dynamique au prix.
Quand r = 0, on remarque que la zone de contact se réduit à 0 comme montré sur la courbe suivante
et donc on n’exercera jamais notre option d’achat avant l’écheance.
[89]: main_call(0, 0.01)

11
On remarque également que le cas d’un dividende nul ne modifie pas notre date d’exercice:
[90]: main_call(0.02,0)

12
Dorénavant, intéressant nous au cas où la condition de bord en a soit nulle(u(a, ) = (exp (a)) =
0), dans ce cas on pourrait y remédier dans le contexte d’une option d’achat par une approche
courante qui est d’utiliser une condition de Neumann à la frontière. Cette condition fixe la dérivée
partielle par rapport à la frontière en a, évitant ainsi le contact indésirable tout en permettant une
spécification appropriée de la frontière.
En effet, considérons une option d’achat où la condition à la frontière est u(a, ) = (exp (a)) = 0,
cette condition crée un contact indésirable. Au lieu de cela, nous pourrions utiliser une condition
de Neumann telle que:
�u/�a(a, ) = 0
à la frontière. Cela assure une dérivée nulle à la frontière, évitant ainsi des valeurs non souhaitées
pour u(a,�). Cette approche est cohérente avec la nature financière du problème, où la dérivée par
rapport à a représente le comportement du prix de l’actif sous-jacent aux extrémités du problème.
En ajustant la condition de bord de cette manière, nous maintenons la cohérence avec les carac-
téristiques financières du problème tout en évitant des résultats indésirables liés au contact à la
frontière.

1.4 Conclusion:
En guise de conclusion, on a pu durant ce travail implémenter la méthode de Gauss Seidel et
l’utiliser sur deux problèmes différents, en remarquant son efficacité quand on est loin des bords
pour le cas de l’option américaine, mais également ses limitations à cause des divergences dans
le cas du problème de la corde. Grâce à ceci, on pourrait justifier l’importance qui est dédiée
aux conditions aux bords dans les problèmes de résolution d’EDP par discrétisation. Ainsi que le
fait que l’utilisation d’autre méthodes plus adéquates pourrait mené pouvoir distinguer davantage
d’améliorations à cette approche, en particulier celle des limitations du nombre d’itérés et éviter la
stagnation du modèle.

13

Vous aimerez peut-être aussi