No estoy completamente seguro por su pregunta, pero voy a suponer que tiene una cesta de $n$ acciones con precios $S_0(t)$ a $S_n(t)$ y se quiere fijar el precio de una opción con un pago de $C(\tau)$ en el momento $\tau$ igual a
\begin{align} C(\tau) = \max\Bigl({\frac 1 n}\sum^n_{i=1} S_i - K, 0\Bigr) \end{align} donde $K$ es el strike de la opción
También voy a hacer la suposición de que cada uno de ellos evoluciona según el movimiento browniano geométrico en la medida RN, por lo que
\begin{align} dS_i = S_i \bigl(r dt + \sigma_i dW_t) \end{align} donde los movimientos brownianos están potencialmente correlacionados con $n \times n$ matriz de correlación $\tilde{\Sigma}$
Esto significa que en el momento $\tau$ cada una de las acciones tiene un precio \begin{align} S_i(\tau) &= S_i(0)\exp \Bigl( (r -{\frac 1 2} \sigma_i^2)\tau + \sigma_i \sqrt{\tau} x_i \Bigr)\\ &= F_i(0) \exp \Bigl( {\frac 1 2} \sigma_i^2\tau + \sigma_i \sqrt{\tau} x_i \Bigr) \end{align} donde he absorbido la $r$ término en el delantero para simplificar el álgebra, y el $x_i$ son variables extraídas de un $n$ -normal multidimensional con media $0$ , varianza $1$ y la matriz de correlación $\tilde{\Sigma}$ desde arriba
Ahora el problema al que nos enfrentamos es que, asumiendo esta dinámica, sabemos cómo valorar una opción sobre una única acción, cuyo precio está distribuido de forma lognormal, utilizando la fórmula BS. Pero, por desgracia, el $\sum^n_{i=0} S_i$ El término en el pago no está distribuido lognormalmente porque es una suma de lognormales, no un producto.
Tenemos dos opciones:
- Precio numérico mediante Monte-Carlo
Aquí está python para hacerlo (aquí, para 5 acciones con una matriz de correlación aleatoria que acabo de hacer)
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from scipy.stats import multivariate_normal
means = np.zeros(5)
corr_mat = np.matrix([[1, 0.1, -0.1, 0, 0], [0.1, 1, 0, 0, 0.2], [-0.1, 0, 1, 0, 0], [0, 0, 0, 1, 0.15], [0, 0.2, 0, 0.15, 1]])
vols = np.array([0.1, 0.12, 0.13, 0.09, 0.11])
cov_mat = np.diag(vols).dot(corr_mat).dot(np.diag(vols))
initial_spots = np.array([100., 100., 100., 100., 100.])
tte = 1.0
strike = 100
seed = 43
num_paths = 50000
results = []
rng = multivariate_normal(means, cov_mat).rvs(size=num_paths, random_state=seed)
for i in range(num_paths):
rns = rng[i]
final_spots = initial_spots * np.exp(-0.5*vols*vols*tte) * np.exp(tte * rns)
results.append(final_spots)
df = pd.DataFrame(results)
df['payoff'] = ((df.sum(axis=1) / 5) - strike).clip(0)
df['payoff'].mean()
da el precio $\sim 2.09$
- Precio APROXIMADAMENTE , utilizando técnicas analíticas
Podemos usar un truco aquí. El precio de la suma de las opciones no está distribuido de forma lognormal, pero el producto de los precios sí, por lo que CAN Fijar analíticamente el precio del contrato con el pago \begin{align} C(\tau) = \max\Bigl(\bigl(\prod^n_{i=1} S_i\bigr)^{\frac 1 n} - K, 0\Bigr) \end{align}
El álgebra es un poco complicada (véase la parte inferior de la respuesta), pero resulta que esto se simplifica a un problema de valoración de opciones vainilla, por lo que podemos valorar la opción utilizando las ecuaciones regulares de BS: \begin{align} C(0) &= \delta \bigl(F\Phi(d_{+}) - K \Phi(d_{-})\bigr)\\ d_{+} &= {\frac {\ln{\frac F K} + {\frac 1 2} \tilde{\sigma}^2 \tau} {\tilde{\sigma}\sqrt{\tau}}}\\ d_{-} &= d_{+} - \tilde{\sigma}\sqrt{\tau} \end{align}
pero los valores que necesitamos insertar para $F$ y $\tilde{\sigma}$ son: \begin{align} \sigma^2 &= {\frac 1 n}\sum_{i=1}^n \sigma_i^2\\ \tilde{\sigma}^2 &= {\frac 1 {n^2}} \sum_{i,j=0}^n \rho_{ij} \sigma_i \sigma_j\\ F &= \Bigl(\prod_{i=1}^n F_i\Bigr)^{\frac 1 n} \cdot \exp\Bigl(-{\frac 1 2} \bigl(\sigma^2 - \tilde{\sigma}^2 \bigr)\tau\Bigr) \end{align}
He implementado eso en scruffy python aquí también:
mod_vol_1 = (vols ** 2).mean()
mod_vol_2 = vols.dot(corr).dot(vols) / len(vols)**2
mod_fwd = np.product(initial_spots)**(1/len(vols)) * np.exp(-0.5*tte*(mod_vol_1 - mod_vol_2))
d_plus = (np.log(mod_fwd / strike) + 0.5 * mod_vol_2 * tte) / np.sqrt(mod_vol_2 * tte)
d_minus = d_plus - np.sqrt(mod_vol_2 * tte)
mod_fwd * norm.cdf(d_plus) - strike * norm.cdf(d_minus)
el precio es $1.87$
¿Cómo nos ayuda esto? En realidad, de dos maneras...
Esto se desarrolló para la cesta de promedios geométricos, pero resulta que podemos utilizar una técnica llamada Coincidencia de momentos para mejorar la aproximación
En primer orden, esto nos da las mismas ecuaciones que las anteriores, excepto que $F$ es en cambio igual a simplemente \begin{align} F &= \Bigl(\prod_{i=1}^n F_i\Bigr)^{\frac 1 n} \end{align}
Si hacemos este ajuste a nuestro desaliñado pitón, igualamos el precio de Monte-Carlo anterior casi exactamente...
mod_vol_1 = (vols ** 2).mean()
mod_vol_2 = vols.dot(corr).dot(vols) / len(vols)**2
mod_fwd = np.product(initial_spots)**(1/len(vols))
d_plus = (np.log(mod_fwd / strike) + 0.5 * mod_vol_2 * tte) / np.sqrt(mod_vol_2 * tte)
d_minus = d_plus - np.sqrt(mod_vol_2 * tte)
mod_fwd * norm.cdf(d_plus) - strike * norm.cdf(d_minus)
el precio es $2.10$
También podemos utilizar la opción geométrica para mejorar nuestro cálculo de MC, utilizando la técnica de Variantes de control que se basa en el hecho de que, dado que el precio de los dos tipos de opciones está muy correlacionado, las trayectorias de MC que sobrevaloran una tenderán a sobrevalorar la otra, y viceversa, lo que nos permite mejorar mucho la convergencia del MC.
Y, efectivamente, están muy correlacionados... aquí hay un gráfico de dispersión de los dos precios a lo largo de las mismas trayectorias (nótese que la cesta geométrica es siempre más barata que la aritmética a lo largo de una trayectoria determinada):