Black Scholes Merton con Python

Gerard Sánchez - 26 de Noviembre de 2020 a las 10:38 - Modelos




El método Black-Scholes de Merton para la valoración de opciones puede ser algo tedioso de calcular a mano aunque tenemos muchas herramientas gratuitas en internet para realizar este cálculo simplemente introduciendo los datos de las fórmulas.

He pensado que puede ser interesante disponer de una herramienta en Python para automatizar este proceso. Será necesario que instalemos la librería SciPy si no la tenemos.

pipenv install SciPy

En el artículo de las griegas resumimos las condiciones necesarias para poder aplicar el modelo correctamente y no veo necesario realizar una explicación del modelo otra vez.

En este artículo me limitaré a analizar el código y a explicarlo para que sea entendible. El código define un modelo BS sin dividendo.

Precio Opción

d1

d2

def d1(S, K, r, Vol, T):
    return (np.log(S/K) + ((r + (Vol**2)/2) * T)) / (Vol* np.sqrt(T))
            
def d2(S, K, r, Vol, T):
    return (np.log(S/K) + ((r - (Vol**2)/2) * T)) / (Vol* np.sqrt(T))

def BSMCall(S, K, r, Vol, T):
    d_uno = d1(S, K, r, Vol, T)
    d_dos = d2(S, K, r, Vol, T)
    return (S*norm.cdf(d_uno)) - (K*np.exp(-r*T)*norm.cdf(d_dos))

def BSMPut(S, K, r, Vol, T):
    d_uno = d1(S, K, r, Vol, T)
    d_dos = d2(S, K, r, Vol, T)
    return (K*np.exp(-r*T)*norm.cdf(-d_dos)) - (S*norm.cdf(-d_uno))

La programación de las fórmulas es sencilla. Para d1 y d2 necesitamos conocer las variables que las componen: precio del subyacente (S), strike de la opción (K), la tasa libre de riesgo (r), volatilidad entendida como desviación estándar (stdev) y tiempo a vencimiento (T).

En el caso de las funciones BSM, necesitamos calcular N(x) con norm.cdf para la función de distribución acumulativa CDF(x).

Función de distribución acumulativa

assets = ['FB']

data = pd.DataFrame()
data = wb.DataReader(assets,data_source='yahoo', start='2020-1-1')['Adj Close']

log_returns = np.log(1+data.pct_change())
Vol = log_returns.std() * 252 **0.5

Este código ya lo conocemos de entradas anteriores.

Seleccionamos el último precio de cierre del subyacente (S), en este caso de $FB y calculamos los retornos logarítmicos a partir de 2020 hasta YTD.

Para el cálculo de la volatilidad necesitamos la desviación estándar de esos retornos log_returns.std() anualizada *252 y elevado a 1/2 (o raíz cuadrada sqrt()).

r = ""    #Risk free rate
K = ""    #Strike
T = ""    #Tiempo a vencimiento

Los parámetros libres del modelo. Debemos escoger discrecionalmente el valor de r en función del bono a 10 años estadounidense por ejemplo o tasas parecidas. El strike de la opción a valorar (K) , tiempo restante a vencimiento (T) y la tasa libre (r) son variables dinámicas que tendremos que introducir manualmente. El precio del subyacente se escoge a través de yahoo finance y el parámetro de la Volatilidad (Vol) viene de la desviación estándar de los resultados logarítmicos del periodo de resultados que escogemos a través del argumento start= y que finalizamos con end=, por ejemplo.
 



 

import numpy as np
import pandas as pd
from math import *
from pandas_datareader import data as wb
from scipy.stats import norm


r = 0.025    #Risk free rate en tanto por uno
K = 125      #Strike
T = 1        #Tiempo a vencimiento

assets = ['FB']
data = pd.DataFrame()
data = wb.DataReader(assets,data_source='yahoo', start='2020-1-1')['Adj Close']

S = data.iloc[-1]

log_returns = np.log(1+data.pct_change())
Vol = log_returns.std() * 252 **0.5

def d1(S, K, r, Vol, T):
    return (np.log(S/K) + ((r + (Vol**2)/2) * T)) / (Vol * np.sqrt(T))
            
def d2(S, K, r, Vol, T):
    return (np.log(S/K) + ((r - (Vol**2)/2) * T)) / (Vol * np.sqrt(T))

def BSMCall(S, K, r, Vol, T):
    d_uno = d1(S, K, r, Vol, T)
    d_dos = d2(S, K, r, Vol, T)
    return (S*norm.cdf(d_uno)) - (K*np.exp(-r*T)*norm.cdf(d_dos))

def BSMPut(S, K, r, Vol, T):
    d_uno = d1(S, K, r, Vol, T)
    d_dos = d2(S, K, r, Vol, T)
    return (K*np.exp(-r*T)*norm.cdf(-d_dos)) - (S*norm.cdf(-d_uno))

Call y Put

Podemos aproximar las derivadas parciales del modelo, también conocidas como las griegas.

En el caso de las opciones de compra:

def BSMCallGreeks(S, K, r, Vol, T):
    d_uno = d1(S, K, r, Vol, T)
    d_dos = d2(S, K, r, Vol, T)
    Delta = norm.cdf(d_uno)
    Gamma = norm.pdf(d_uno)/(S*Vol*sqrt(T)
    Theta = -(S*Vol*norm.pdf(d_uno))/(2*sqrt(T) - r*K*exp( -r*T)*norm.cdf(d_dos)
    Vega = S *sqrt(T)*norm.pdf(d_uno)
    Rho = K*T*exp(-r*T)*norm.cdf(d_dos)
    return Delta, Gamma, Theta, Vega , Rho

Griegas opciones call


En el caso de las opciones de venta:

def BSMPutGreeks(S, K, r, Vol, T):
    d_uno = d1(S, K, r, Vol, T)
    d_dos = d2(S, K, r, Vol, T)
    Delta = norm.cdf(-d_uno)
    Gamma = norm.pdf(d1)/(S*Vol*sqrt(T))
    Theta = -(S*Vol*norm.pdf(d_uno)) / (2*sqrt(T))+ r*K * exp(-r*T) * norm.cdf(-d_uno)
    Vega = S *sqrt(T) * norm.pdf(d_uno)
    Rho = -K*T*exp(-r*T) * norm.cdf(-d_dos)
    return Delta, Gamma, Theta, Vega, Rho

Griegas opciones put


Para añadir un dividendo contínuo, sólo habría que añadir un parámetro "d": BSM(S, K, r, Vol, T, d) y modificar las fórmulas.


292 visitas
2    Login to like
Categorías:
 Estadísticas   Random   Gestión pasiva   Análisis técnico   Modelos   CEO   Mapas mentales   Liberalismo   Python   Growth   Niusleta   Ahorro   Recursos humanos   Inmobiliario   Fiscalidad   Value investing   Dividendos   Contabilidad   Marketing   Riesgo   IF   Cursos   Opciones   Bolsa