Clase 14: Opciones con barreras

Juan Diego Sánchez Torres,

Profesor, MAF ITESO

  • Departamento de Matemáticas y Física
  • dsanchez@iteso.mx
  • Tel. 3669-34-34 Ext. 3069
  • Oficina: Cubículo 4, Edificio J, 2do piso

1. Teoría básica

En primer lugar, para poder bajar precios y información sobre opciones de Yahoo, es necesario cargar algunos paquetes de Python. En este caso, el paquete principal será Pandas. También, se usarán el Scipy y el Numpy para las matemáticas necesarias y, el Matplotlib y el Seaborn para hacer gráficos de las series de datos.


In [1]:
#importar los paquetes que se van a usar
import pandas as pd
import pandas_datareader.data as web
import numpy as np
import datetime
from datetime import datetime
import scipy.stats as stats
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
#algunas opciones para Python
pd.set_option('display.notebook_repr_html', True)
pd.set_option('display.max_columns', 6)
pd.set_option('display.max_rows', 10)
pd.set_option('display.width', 78)
pd.set_option('precision', 3)

Para un activo con precio $S_t$, se considera una opción de la siguiente forma \begin{equation} V_T=u(t)F_T \end{equation} para $0\leq t\leq T$. En este caso, $F_T=\max(S_T-K,0)$ para una opción tipo call o $F_T=\max(K-S_T,0)$ para una opción tipo put. La función $u(t)$ est\'a definida en $0\leq t\leq T$, toma el valor de uno sí se cumple cierta condición y el valor de cero en otra caso.

Por otra lado, para $B>0$ y $0<t<T$ se dice que $S_t$ ha superado la barrera $B$ sí $S_0<B$ y $S_t>B$ para alg\'un tiempo $t$ en el periodo considerado. Similarmente, se dice que $S_t$ ha caído por debajo de la barrera $B$ sí $S_0>B$ y $S_t<B$ para alg\'un tiempo $t$ en el periodo considerado.

Finalmente, para un enunciado $x$, se define la función indicadora $I(x)$ como $I(x)=1$ si $x$ se cumple e $I(x)=0$ en otro caso.

Se esta forma, pueden definirse las siguientes acciones

  • Up-and-out: Sí $S_0<B$, entonces $u(t)=I(S_t<B)$.
  • Down-and-out: Sí $S_0>B$, entonces $u(t)=I(S_t>B)$.
  • Up-and-in: Sí $S_0<B$, entonces $u(t)=I(S_t>B)$.
  • Down-and-in: Sí $S_0>B$, entonces $u(t)=I(S_t<B)$.

Así se se pueden definirse ocho nuevos tipos de opciones.

  • Up-and-out call: Sí $S_0<B$, $C_t^{uo}=\max\{S_T-K,0\}I(S_t<B)$
  • Down-and-out call: Sí $S_0>B$, $C_t^{do}=\max\{S_T-K,0\}I(S_t>B)$
  • Up-and-in call: Sí $S_0<B$, $C_t^{ui}=\max\{S_T-K,0\}I(S_t>B)$
  • Down-and-in call: Sí $S_0>B$, $C_t^{di}=\max\{S_T-K,0\}I(S_t<B)$
  • Up-and-out put: Sí $S_0<B$, $P_t^{uo}=\max\{K-S_T,0\}I(S_t<B)$
  • Down-and-out put: Sí $S_0>B$, $P_t^{do}=\max\{K-S_T,0\}I(S_t>B)$
  • Up-and-in put: Sí $S_0<B$, $P_t^{ui}=\max\{K-S_T,0\}I(S_t>B)$
  • Down-and-in put: Sí $S_0>B$, $P_t^{di}=\max\{K-S_T,0\}I(S_t<B)$

A las del tipo up-and-out y down-and-out se les conoce como opciones knock-out. De la misma forma, a las del tipo up-and-in y down-and-in se les conoce como opciones knock-in.

Note que estas son opciones dependientes de la trayectoria del precio, dado que $u(t)$ depende de $S_t$.

3. Gráficos del Pay Off


In [11]:
def call_payoff(ST, K):
    return max(0, ST-K)

In [12]:
call_payoff(25, 30)


Out[12]:
0

In [13]:
def call_payoffs(STmin, STmax, K, step=1):
    maturities = np.arange(STmin, STmax+step, step)
    payoffs = np.vectorize(call_payoff)(maturities, K)
    df = pd.DataFrame({'Strike': K, 'Payoff': payoffs}, index=maturities)
    df.index.name = 'Precio de maduración'
    return df

In [14]:
call_payoffs(10,25,15)


Out[14]:
Payoff Strike
Precio de maduración
10 0 15
11 0 15
12 0 15
13 0 15
14 0 15
... ... ...
21 6 15
22 7 15
23 8 15
24 9 15
25 10 15

16 rows × 2 columns


In [15]:
def plot_call_payoffs(STmin, STmax, K, step=1):
    payoffs = call_payoffs(STmin, STmax, K, step)
    plt.ylim(payoffs.Payoff.min() - 10, payoffs.Payoff.max() + 10)
    plt.ylabel("Payoff")
    plt.xlabel("Precio de maduración")
    plt.title('Payoff call, Precio strike={0}'.format(K))
    plt.xlim(STmin, STmax)
    plt.plot(payoffs.index, payoffs.Payoff.values);

In [16]:
plot_call_payoffs(10, 25, 15)



In [17]:
def put_payoff(ST, K):
    return max(0, K-ST)

In [18]:
put_payoff(25, 30)


Out[18]:
5

In [19]:
def put_payoffs(STmin, STmax, K, step=1):
    maturities = np.arange(STmin, STmax+step, step)
    payoffs = np.vectorize(put_payoff)(maturities, K)
    df = pd.DataFrame({'Strike': K, 'Payoff': payoffs}, index=maturities)
    df.index.name = 'Precio de maduración'
    return df

In [20]:
put_payoffs(10,25,15)


Out[20]:
Payoff Strike
Precio de maduración
10 5 15
11 4 15
12 3 15
13 2 15
14 1 15
... ... ...
21 0 15
22 0 15
23 0 15
24 0 15
25 0 15

16 rows × 2 columns


In [21]:
def plot_put_payoffs(STmin, STmax, K, step=1):
    payoffs = put_payoffs(STmin, STmax, K, step)
    plt.ylim(payoffs.Payoff.min() - 10, payoffs.Payoff.max() + 10)
    plt.ylabel("Payoff")
    plt.xlabel("Precio de maduración")
    plt.title('Payoff put, Precio strike={0}'.format(K))
    plt.xlim(STmin, STmax)
    plt.plot(payoffs.index, payoffs.Payoff.values);

In [22]:
plot_put_payoffs(10, 25, 15)



In [23]:
def call_pnl_buyer(ct, K, STmin, STmax, step = 1):
    maturities = np.arange(STmin, STmax+step, step)
    payoffs = np.vectorize(call_payoff)(maturities, K)
    df = pd.DataFrame({'Strike': K, 'Payoff': payoffs, 'Prima': ct, 'PnL': payoffs-ct}, index=maturities)
    df.index.name = 'Precio de maduración'
    return df

In [24]:
call_pnl_buyer(12, 15, 10, 35)


Out[24]:
Payoff PnL Prima Strike
Precio de maduración
10 0 -12 12 15
11 0 -12 12 15
12 0 -12 12 15
13 0 -12 12 15
14 0 -12 12 15
... ... ... ... ...
31 16 4 12 15
32 17 5 12 15
33 18 6 12 15
34 19 7 12 15
35 20 8 12 15

26 rows × 4 columns


In [25]:
def call_pnl_seller(ct, K, STmin, STmax, step = 1):
    maturities = np.arange(STmin, STmax+step, step)
    payoffs = np.vectorize(call_payoff)(maturities, K)
    df = pd.DataFrame({'Strike': K, 'Payoff': payoffs, 'Prima': ct, 'PnL': ct-payoffs}, index=maturities)
    df.index.name = 'Precio de maduración'
    return df

In [26]:
call_pnl_seller(12, 15, 10, 35)


Out[26]:
Payoff PnL Prima Strike
Precio de maduración
10 0 12 12 15
11 0 12 12 15
12 0 12 12 15
13 0 12 12 15
14 0 12 12 15
... ... ... ... ...
31 16 -4 12 15
32 17 -5 12 15
33 18 -6 12 15
34 19 -7 12 15
35 20 -8 12 15

26 rows × 4 columns


In [27]:
def call_pnl_combined(ct, K, STmin, STmax, step = 1):
    maturities = np.arange(STmin, STmax+step, step)
    payoffs = np.vectorize(call_payoff)(maturities, K)
    df = pd.DataFrame({'Strike': K, 'Payoff': payoffs, 'Prima': ct, 'PnLcomprador': payoffs-ct, 'PnLvendedor': ct-payoffs}, index=maturities)
    df.index.name = 'Precio de maduración'
    return df

In [28]:
call_pnl_combined(12, 15, 10, 35)


Out[28]:
Payoff PnLcomprador PnLvendedor Prima Strike
Precio de maduración
10 0 -12 12 12 15
11 0 -12 12 12 15
12 0 -12 12 12 15
13 0 -12 12 12 15
14 0 -12 12 12 15
... ... ... ... ... ...
31 16 4 -4 12 15
32 17 5 -5 12 15
33 18 6 -6 12 15
34 19 7 -7 12 15
35 20 8 -8 12 15

26 rows × 5 columns


In [29]:
def put_pnl_buyer(ct, K, STmin, STmax, step = 1):
    maturities = np.arange(STmin, STmax+step, step)
    payoffs = np.vectorize(put_payoff)(maturities, K)
    df = pd.DataFrame({'Strike': K, 'Payoff': payoffs, 'Prima': ct, 'PnL': payoffs-ct}, index=maturities)
    df.index.name = 'Precio de maduración'
    return df

In [30]:
put_pnl_buyer(2, 15, 10, 30)


Out[30]:
Payoff PnL Prima Strike
Precio de maduración
10 5 3 2 15
11 4 2 2 15
12 3 1 2 15
13 2 0 2 15
14 1 -1 2 15
... ... ... ... ...
26 0 -2 2 15
27 0 -2 2 15
28 0 -2 2 15
29 0 -2 2 15
30 0 -2 2 15

21 rows × 4 columns


In [31]:
def put_pnl_seller(ct, K, STmin, STmax, step = 1):
    maturities = np.arange(STmin, STmax+step, step)
    payoffs = np.vectorize(put_payoff)(maturities, K)
    df = pd.DataFrame({'Strike': K, 'Payoff': payoffs, 'Prima': ct, 'PnL': ct-payoffs}, index=maturities)
    df.index.name = 'Precio de maduración'
    return df

In [32]:
put_pnl_seller(2, 15, 10, 30)


Out[32]:
Payoff PnL Prima Strike
Precio de maduración
10 5 -3 2 15
11 4 -2 2 15
12 3 -1 2 15
13 2 0 2 15
14 1 1 2 15
... ... ... ... ...
26 0 2 2 15
27 0 2 2 15
28 0 2 2 15
29 0 2 2 15
30 0 2 2 15

21 rows × 4 columns


In [33]:
def put_pnl_combined(ct, K, STmin, STmax, step = 1):
    maturities = np.arange(STmin, STmax+step, step)
    payoffs = np.vectorize(put_payoff)(maturities, K)
    df = pd.DataFrame({'Strike': K, 'Payoff': payoffs, 'Prima': ct, 'PnLcomprador': payoffs-ct, 'PnLvendedor': ct-payoffs}, index=maturities)
    df.index.name = 'Precio de maduración'
    return df

In [34]:
put_pnl_combined(2, 15, 10, 30)


Out[34]:
Payoff PnLcomprador PnLvendedor Prima Strike
Precio de maduración
10 5 3 -3 2 15
11 4 2 -2 2 15
12 3 1 -1 2 15
13 2 0 0 2 15
14 1 -1 1 2 15
... ... ... ... ... ...
26 0 -2 2 2 15
27 0 -2 2 2 15
28 0 -2 2 2 15
29 0 -2 2 2 15
30 0 -2 2 2 15

21 rows × 5 columns


In [35]:
def plot_pnl(pnl_df, okind, who):
    plt.ylim(pnl_df.Payoff.min() - 10, pnl_df.Payoff.max() + 10)
    plt.ylabel("Ganancia/pérdida")
    plt.xlabel("Precio de maduración")
    plt.title('Ganancia y pérdida de una opción {0} para el {1}, Prima={2}, Strike={3}'.format(okind, who, pnl_df.Prima.iloc[0],
    pnl_df.Strike.iloc[0]))
    plt.ylim(pnl_df.PnL.min()-3, pnl_df.PnL.max() + 3)
    plt.xlim(pnl_df.index[0], pnl_df.index[len(pnl_df.index)-1])
    plt.plot(pnl_df.index, pnl_df.PnL)
    plt.axhline(0, color='g');

In [36]:
plot_pnl(call_pnl_buyer(12, 15, 10, 35), "call", "comprador")



In [37]:
plot_pnl(call_pnl_seller(12, 15, 10, 35), "call", "vendedor")



In [38]:
plot_pnl(put_pnl_buyer(2, 15, 10, 30), "put", "comprador")