Pricing des options avec le modèle de Cox-Ross-Rubinstein en C++

Parmi les modèles utilisés pour le pricing des options, on a le célébrissime modèle de Black-Scholes-Merton(1973) mais aussi le non-moins célèbre modèle de Cox-Ross-Rubinstein(1979) qui est un modèle discret contrairement au premier et qui a la cote parmi les modèles discrets. Il a la particularité d’être simple et intuitif, il vous épargne toute l’armada mathématique (les processus et équations différentielles stochastiques) sous bassement du modèle de Black-Scholes-Merton et ne démérite en terme de résultats. En effet, avec un peu de gymnastique mathématique, on peut aboutir au modèle de Black-Scholes-Merton.

Notre article ne porte pas sur la dérivation du modèle de Black-Scholes-Merton mais celle du Modèle de Cox-Ross-Rubinstein et de son implémentation en C++ dans un paradigme Orienté Objet.

binomial

Exemple d’arbre binomial après 3 itérations (Extrait du livre : The Theory and Practice of Investment Management)

 

Modèle Binomial de Cox-Ross-Rubinstein :

Description du modèle dans le cadre d’une option européenne

En l’Absence d’Opportunité d’Arbitrage et en supposant notamment que le prix du sous-jacent S, ne puisse prendre à une itération i de T que la valeur S_i^u quand elle évolue à la hausse et S_i^d lors d’une évolution à la baisse, telle que :

    \[ S_i = \begin{cases} S^u_i = S_{i-1}\cdot u\quad\quad\text{avec une probabilit\'e $p$}\\S^d_i = S_{i-1}\cdot d\quad\quad\text{avec une probabilit\'e $1-p$}\]

Nous pouvons alors définir la valeur S_{j,i} par rapport à la valeur S_0 ( le prix de l’actif sous-jacent à la date du contrat) comme un arbre binomial dont la valeur à l’issue de i itération et pour j hausse vaut :

(1)   \begin{equation*}S_0\cdot u^j\cdot d^{i-j} \quad\text{avec}\quad i = 0,1,\dots,n-1, n\end{equation*}

S’il est possible de déterminer les valeurs de S à chaque nœud d’un arbre, il est donc aussi possible de calculer la valeur de l’option V à chacun de ces nœuds  comme ceci : 

(2)   \begin{equation*}V_{j,i}= \begin{cases} max(0,S_{j,i}- K)\quad\quad\text{dans le cas d'un call}\\max(0,K-S_{j,i})\quad\quad\text{dans le cas d'un put}\end{equation*}

Prenons un exemple de Call après une itération la valeur C_1 à chaque nœud vaut :

    \[C_1= \begin{cases} C^u_1 = max(0,S^u_1- K)\quad\quad\text{avec une probabilit\'e $p$}\\C^d_1 = max(0,S^d_1- K) = 0\quad\quad\text{avec une probabilit\'e $1-p$}\]

Donc d’après ce développement, il est possible de déterminer la valeur de C_1 selon que S^u ou S^d se réalise. Mais ce que nous nous voulons c’est la valeur C_0 de l’option Call.

C’est là qu’il faut faire appel à un ingrédient incontournable l’hypothèse de Risque Neutre qui veut que :

  • – L’espérance de rendement de l’actif sous-jacent est égale au taux de rendement de l’actif sans risque r
  • r, le  taux de l’actif sans risque soit le taux d’actualisation.

Et dans ce cas :

    \[C_0 = [p\cdot C_1^u-(1-p)\cdot C_1^d]e^{-r}\]

ou de manière générale, on peut calculer la valeur d’une option call comme put  de type européenne(dont l’exercice ne peut advenir qu’à la date d’expiration):

(3)   \begin{equation*}V_{j,i}=[p\cdot V_{j+1,i+1} + (1-p)\cdot V_{j,i+1}]e^{-r\cdot\Delta t} \end{equation*}

ou si l’on préfère cette écriture  

(4)   \begin{equation*}V_{j,i}=[p\cdot V_{i+1}^u+ (1-p)\cdot V_{i+1}^d]e^{-r\cdot\Delta t} \end{equation*}

Avec \Delta t=\frac{T}{n}T est la maturité de l’option et n le nombre d’itération ou de niveau de notre arbre binomial. Et p la probabilité risque neutre qui vaut

(5)   \begin{equation*}p = \frac{e^r-d}{u-d}\end{equation*}

par ce qu’en effet d’après la première conséquence de l’hypothèse risque neutre : e^r = p\cdot u + (1-p)\cdot d

Par ailleurs, ils nous restent encore deux paramètres dont nous n’avons pas encore déterminés les valeurs, il s’agit de u et d. De combien évolue le sous-jacent- il à la hausse u et à la baisse d ?

Pour trouver ces valeurs, Cox, Ross et Rubinstein vont tout simplement les extraire de l’expression de la variance \sigma^2\Delta t et en remplaçant le p par l’équation (5) et après simplification des membres avec des dégrés supérieur ou égal à \Delta t^2, on obtient que :

(6)   \begin{equation*}u=e^{\sigma\sqrt{\Delta t}}\quad\quad\quad\quad\quad d=e^{-\sigma\sqrt{\Delta t}}\end{equation*}

Cas particulier de l’option américaine

Contrairement à une option européenne qui attend d’être exercée à la date d’expiration, l’option américaine, peut être exercée en tout point optimal entre la date de signature du contrat et la date d’expiration. Ainsi, à chaque nœud au lieu de considérer seulement [p\cdot V_{j+1,i+1} + (1-p)\cdot V_{j,i+1}]e^{-r\cdot\Delta t} on comparera cette dernière à S_0\cdot u^j\cdot d^{i-j}-K dans le cas d’un call et K-S_0\cdot u^j\cdot d^{i-j} dans le cas d’un put  :

(7)   \begin{equation*}V_{j,i}=max([p\cdot V_{j+1,i+1} + (1-p)\cdot V_{j,i+1}]e^{-r\cdot\Delta t} ,S_0\cdot u^j\cdot d^{i-j}-K)\end{equation*}

dans le cas d’un call et 

(8)   \begin{equation*}V_{j,i}=max([p\cdot V_{j+1,i+1} + (1-p)\cdot V_{j,i+1}]e^{-r\cdot\Delta t} ,K-S_0\cdot u^j\cdot d^{i-j})\end{equation*}

si c’est un call.

Nombre d’itération et convergence du modèle CRR vers le Modèle de BSM

Prenons une option de type call européen ayant les caractéristiques suivantes : Prix spot 35, prix d’exercice 36, taux d’intérêt sans risque 5%(annuel), la volatilité 30%(annuelle), maturité 1(annuelle). Normalement la valeur d’un tel call européen pour Black-Scholes-Merton vaut 4.5169.

Voyons maintenant avec l’arbre binomial de Cox-Ross-Rubinstein. Considérons d’abord que le nombre d’itération est de N = 1, nous pouvons calculer : u= e^{0.3\cdot\sqrt{1/1}}=1.35, donc d = 1/u=0.74 et p=(e^{0.05/1}-0.74)/(1.35-0.74)=0.51 et après bifurcation on aura : call = [11.25\cdot 0.51+0\cdot (1-0.51)]e^{-0.05\cdot 1}=5.45.

Puis pou N=2 : u= e^{0.3\cdot\sqrt{1/2}}=1.24, donc d = 1/u=0.81 et p=(e^{0.05/2}-0.81)/(1.24-0.81)=0.51 et après bifurcation on aura ce que le call = [17.5\cdot0.51^2+2\cdot0\cdot(1-0.51)\cdot 0.51]e^{-0.05\cdot 1}=4.27 :

bin1

Maintenant on peut observer comme le montre la figure ci-dessous(en abscisse le nombre d’itération et en ordonnée la valeur de l’option) et celle ci-dessus que lorsque le nombre d’itération est grande N\rightarrow+\infty et par conséquence \Delta t \rightarrow 0, la valeur d’une option calculée à la manière de CRR (put ou call) donnera avec les mêmes paramètres la valeur obtenue avec le modèle de BSM.

convergence

Implémentation du modèle Binomial de CRR en C++

Design et Description des classes : la classe de base CRRBinomialTree

Pour les besoins de l’implémentation nous allons adopter l’architecture du diagramme ci-dessous. En effet, nous définirons une classe mère CRRBinomialTree pour fournir les différents paramètres de pricing selon le modèle de CRR aux classes filles nommément EuropeanOption et AmericanOption.

L’idée est de tirer profit du polymorphisme de ces objets pour plus de souplesses en redéfinissant certaines méthodes membres de la classe de base à savoir price() et display() dans les classes filles.

umlbinomail

Par ailleurs, nous ne voulons pas que l’utilisateur final puisse avoir accès aux fonctions getStock(),payOff(), et Up()/Down(), qui ne sont dans notre cas précis que des fonctions intermédiaires.D’où l’intérêt de les déclarer comme protégées, ainsi seule les classes filles peuvent en faire usage. Elles permettent de déterminer respectivement, le prix du sous-jacent à un nœud de l’arbre Cf. équation (1), le pay Off Cf.equation (2) et les deux relations de l’équation (6).

Aussi pour finir nous avons les méthodes usuelles d’une classe digne de ce nom à savoir les constructeurs, les accesseurs/mutateurs et le destructeur.

Héritage : les classes filles AmericanOption et EuropeanOption

Comme énoncé précédemment,  les classes filles vont redéfinir les méthodes price() et display(). Cette dernière n’affichera que les différents caractéristiques du modèles et la valeur de l’options. Les constructeurs des classes filles vont permettre comme on peut le voir ci-dessous, d’ajouter un paramètre additionnel à savoir le type “call” ou “put”.

Maintenant si l’on s’intéresse de près à la fonction price() dont vous verrez le corps dans les blocs de codes plus bas (American.cpp, European.cpp). On remarque d’abord l’utilisation de la routine for pour remplir un tableau permettant l’allocation dynamique de mémoire pour N+1 éléments,( d’où l’usage de pointeur si vous n’êtes fans des pointeurs utiliser la librairie vector )   avec les valeurs de l’options c’est les lignes suivantes :

avec getStock() on récupéré la valeur du titre ensuite avec payOff() on détermine le pay-off  selon le type call ou put au niveau des feuilles de notre arbre. Dans la suite de la fonction, nous implémentons la relation décrite dans l’équation (3) :

Qui va calculer la valeur actuelle des pay-off et ceci de façon récursive en commençant du dernier élément du tableau au premier. Et comme c’est un tableau pour retourner le premier l’élément qui contiendrait à la fin du processus la valeur de l’option on renvoie *v. La version Américaine de la fonction diffère seulement au niveau des 2 lignes suivantes :

Ces deux lignes sont la traduction de l’équation (7) . Aussi, autres points importants c’est l’utilisation CRRBinomialTree:: ,l’opérateur de résolution de portée permet d’accéder aux méthodes membres public de la classe mère. Vous constaterez donc que les méthodes membres protected, n’en ont pas besoin.
Par ailleurs, nous allons invoquer le constructeur de la classe mère dans la définition des constructeur des classes filles. Pour finir voici la définition des trois classes :

Application numérique :

Nous allons montrer quelques utilisations des objets issus des classes précédemment décrites. Faites attention à l’utilisation des pointeurs n’oubliez pas les symboles *  et ->  là où il faut. Et à la fin utiliser delete pour les détruire enfin de libérer de la mémoire.

Résultat :

Comme on peut le voir la rapidité d’exécution malgré le grand nombre de routine utiliser, fait du C++ un langage de choix pour un Quant !

Nous obtenons au finish la même valeur qu’avec le modèle de Black-Scholes and Merton 4.5169 précédement fourni dans l’exemple et que vous pouvez vérifier chez vous avec Excel.

Like