<jupyter_start><jupyter_text>Simulación de procesos financieros. **Nombres:** <NAME> y <NAME>**Fecha:** 23 de Abril del 2021.**Expediente** : 709288 y 711469.**Profesor:** <NAME>. Tarea 9: Clase 22**Link al repositorio en Github**: https://github.com/Joseancg7/Tarea9_AERodriguez_JACasta-o   Tarea: Replicar el procedimiento anterior para valoración de opciones 'call', pero en este caso para opciones tipo 'put' y compararlo con el valor teórico de la ecuación de Black-Scholes.$$ P(S(t),t)=max\{K-S(T),0\} \rightarrow \text{En el caso de Put}$$   Solución José Antonio<jupyter_code>#importar los paquetes que se van a usar
import pandas as pd
import pandas_datareader.data as web
import numpy as np
import datetime
import matplotlib.pyplot as plt
import scipy.stats as st
import seaborn as sns
%matplotlib inline
#algunas opciones para Pandas
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)
# Nio
nio = web.YahooOptions('NIO')
nio_opt = nio.get_all_data().reset_index()
nio_opt.set_index('Expiry')
#Precio del activo subyacente
nio_opt.Underlying_Price[0]
#Datos de la opcion
nio_opt.loc[0, 'JSON']
#Fechas que expiran
pd.set_option('display.max_rows', 10)
nio_opt.loc[:, 'Expiry']
#Busqueda por tipo "compra de put" en cierta fecha
fecha1 = '2022-01-21'
fecha2 = '2023-01-20'
put06_f1 = nio_opt.loc[(nio_opt.Expiry== fecha1) & (nio_opt.Type=='put')]
put06_f2 = nio_opt.loc[(nio_opt.Expiry== fecha2) & (nio_opt.Type=='put')]
put06_f1
# para los put de la fecha 1
ax = put06_f1.set_index('Strike').loc[:, 'IV'].plot(figsize=(8,6))
ax.axvline(put06_f1.Underlying_Price.iloc[0], color='g');
# para los put de la fecha 2
ax = put06_f2.set_index('Strike').loc[:, 'IV'].plot(figsize=(8,6))
ax.axvline(put06_f2.Underlying_Price.iloc[0], color='g');
# Función para descargar precios de cierre ajustados:
def get_adj_closes(tickers, start_date=None, end_date=None):
    # Fecha inicio por defecto (start_date='2010-01-01') y fecha fin por defecto (end_date=today)
    # Descargamos DataFrame con todos los datos
    closes = web.DataReader(name=tickers, data_source='yahoo', start=start_date, end=end_date)
    # Solo necesitamos los precios ajustados en el cierre
    closes = closes['Adj Close']
    # Se ordenan los índices de manera ascendente
    closes.sort_index(inplace=True)
    return closes
#Precios de cierre de Nio hasta la fecha
ticker = ['NIO']
start_date = '2018-01-01'

closes_nio = get_adj_closes(ticker, start_date)
closes_nio.plot(figsize=(8,5));
plt.legend(ticker);
#función para obtener rends logaritmicos
def calc_daily_ret(closes):
    return np.log(closes/closes.shift(1)).iloc[1:]
#rends logaritmicos
ret_nio = calc_daily_ret(closes_nio)
ret_nio.plot(figsize=(8,6));
#seleccion de opcion
K = 80# strike price
indice_opt = nio_opt.loc[(nio_opt.Type=='put') & (nio_opt.Strike==K) & (nio_opt.Expiry=='2022-01-21')]
indice_opt
i_opt= indice_opt.index
opcion_valuar = nio_opt.loc[i_opt[0]]
opcion_valuar['JSON']
print('Precio del activo subyacente actual = ',opcion_valuar.Underlying_Price)<jupyter_output>Precio del activo subyacente actual =  40.6401<jupyter_text>Simulación de precios usando rendimiento simple y logarítmico<jupyter_code># Obtenemos el rendimiento simple
Ri = closes_nio.pct_change(1).iloc[1:]
# Obtenemos su media y desviación estándar de los rendimientos
mu_R = Ri.mean()[0]
sigma_R = Ri.std()[0]
Ri
from datetime import date

# Encontrar la fecha de hoy en fomato timestamp
today = pd.to_datetime(date.today())

# Obtener fecha de cierre de la opción a valuar
expiry = opcion_valuar.Expiry

nscen = 10000

# Generar rangos de fechas de días hábiles
dates = pd.date_range(today, expiry, freq='B')
ndays = len(dates)
dates
# Simular los rendimientos
# Rendimiento diario 
dt = 1
# Z ~ N(0,1) normal estándar (ndays, nscen)
Z = np.random.randn(ndays, nscen)

# Simulación normal de los rendimientos
Ri_dt = pd.DataFrame(Z * sigma_R * np.sqrt(dt) + mu_R * dt, index=dates)
Ri_dt
# Simulación del precio
S_0 = opcion_valuar.Underlying_Price
S_T = S_0*(1+Ri_dt).cumprod()
S_T.iloc[0,:] = S_0

# Se muestran los precios simulados con los precios descargados
pd.concat([closes_nio, S_T.iloc[:, :10]]).plot(figsize=(8,6));
plt.title('Simulación de precios usando rendimiento simple');<jupyter_output><empty_output><jupyter_text>Rendimiento Logarítmico<jupyter_code># Calcular rendimiento logarítmico
ri = calc_daily_ret(closes_nio)

# Usando la media y desviación estándar de los rendimientos logarítmicos
mu_r = ri.mean()[0]
sigma_r = ri.std()[0]

# Simulación del rendimiento
dt = 1
Z = np.random.randn(ndays, nscen)
sim_ret_ri = pd.DataFrame(mu_r * dt + Z * sigma_r * np.sqrt(dt), index=dates )

# Simulación del precio
S_0 = closes_nio.iloc[-1,0]
S_T2 = S_0*np.exp(sim_ret_ri.cumsum())

# Se muestran los precios simulados con los precios descargados
# pd.concat([closes_aapl,S_T2]).plot(figsize=(8,6));
# plt.title('Simulación de precios usando rendimiento logarítmico');

# from sklearn.metrics import mean_absolute_error
e1 = np.abs(S_T-S_T2).mean().mean()
e1
print('Las std usando rendimientos logarítmicos y simples son similares')
sigma_R, sigma_r<jupyter_output>Las std usando rendimientos logarítmicos y simples son similares<jupyter_text>Con los precios simulados debemos de encontrar el valor de la opción según la función de pago correspondiente. Para este caso es:$$max\{K-S(T),0\}$$<jupyter_code>opcion_valuar['JSON']<jupyter_output><empty_output><jupyter_text>Valuación usando el modelo de Black and Scholes<jupyter_code>#media y desviacion estandar
mu = ret_nio.mean()[0]
sigma = ret_nio.std()[0]
mu, sigma
#Tomamos la tasa libre de riesgo
# Tasa de bonos de 1 yr de fecha 22/04/2021 -> 6%
r = 0.006/360 # Tasa diaria
#simulamos 10 escenarios desde hoy hasta su fin
from datetime import date

today = pd.Timestamp(date.today())
expiry = opcion_valuar.Expiry

dates = pd.date_range(start=today, end=expiry, freq='B')

ndays = len(dates)
nscen = 10
dates
#rends simulados
sim_ret = pd.DataFrame(sigma*np.random.randn(ndays,nscen)+r, index=dates)
sim_ret.cumsum()
# Las columnas son los escenarios y las filas son las días de contrato
#escenarios de precios respectivos
S0 = closes_nio.iloc[-1,0]  # Condición inicial del precio a simular
sim_closes = S0*np.exp(sim_ret.cumsum())
sim_closes.iloc[0, :] = S0
sim_closes.plot(figsize=(8,6));
sim_closes
# Se muestran los precios simulados con los precios descargados
pd.concat([closes_nio,sim_closes]).plot(figsize=(8,6));
opcion_valuar
from datetime import date
Hoy = date.today()

# strike price de la opción
K = opcion_valuar['JSON']['strike']  

# Fechas a simular
dates = pd.date_range(start= Hoy, periods = ndays, freq='B')

# Escenarios y número de días
ndays = len(dates)
nscen = 100000

# Condición inicial del precio a simular
S0 = closes_nio.iloc[-1,0]  

# simular rendimientos
sim_ret = pd.DataFrame(sigma*np.random.randn(ndays,nscen)+r,index=dates)

# Simular precios
sim_closes = S0*np.exp(sim_ret.cumsum())
# Valor del put europeo
put = pd.DataFrame({'Prima':np.exp(-r*ndays) \
              *np.fmax(K-sim_closes, 0).mean(axis=1)}, index=dates)
put.plot();
#Valuación de la opción:
put.iloc[-1]
#Con intervalo de confianza del 99%
confianza = 0.99
sigma_est = sim_closes.iloc[-1].sem()
mean_est = put.iloc[-1].Prima
i2 = st.norm.interval(confianza, loc=mean_est, scale=sigma_est)
print(i2)<jupyter_output>(34.27432490539655, 35.39180568642377)<jupyter_text>Precios simulados usando técnicas de reducción de varianza<jupyter_code># Usando muestreo estratificado----> #estratros = nscen
U = (np.arange(0,nscen)+np.random.rand(ndays,nscen))/nscen
Z = st.norm.ppf(U)

sim_ret2 = pd.DataFrame(sigma*Z+r,index=dates)
sim_closes2 = S0*np.exp(sim_ret.cumsum())

# Función de pago
strike = pd.DataFrame(K*np.ones([ndays,nscen]), index=dates)
put = pd.DataFrame({'Prima':np.exp(-r*ndays) \
              *np.fmax(strike-sim_closes2,np.zeros([ndays,nscen])).T.mean()}, index=dates)
put.plot();
#Valuación de la opción:
put.iloc[-1]
#Con intervalo de confianza del 99%
confianza = 0.99
sigma_est = sim_closes2.iloc[-1].sem()
mean_est = put.iloc[-1].Prima
i2 = st.norm.interval(confianza, loc=mean_est, scale=sigma_est)
print(i2)<jupyter_output>(34.27432490539655, 35.39180568642377)<jupyter_text>Análisis de la distribución de los rendimientos  Ajustando Norm (no se ajusta muy bien)<jupyter_code>ren = calc_daily_ret(closes_nio) # rendimientos 
y,x,_ = plt.hist(ren['NIO'],bins=50,density=True,label='Histograma rendimientos')

mu_fit,sd_fit = st.norm.fit(ren) # Se ajustan los parámetros de una normal
# Valores máximo y mínimo de los rendiemientos a generar
ren_max = max(x);ren_min = min(x)
# Vector de rendimientos generados
ren_gen = np.arange(ren_min,ren_max,0.001)
# Generación de la normal ajustado con los parámetros encontrados
curve_fit = st.norm.pdf(ren_gen,loc=mu_fit,scale=sd_fit)
plt.plot(ren_gen,curve_fit,label='Distribución ajustada')
plt.legend()
plt.show()<jupyter_output><empty_output><jupyter_text>Ajustando t (muy buen ajuste)<jupyter_code># rendimientos 
ren = calc_daily_ret(closes_nio) 

# Histograma de los rendimientos
y, x, _ = plt.hist(ren['NIO'], bins=50, density=True, label='Histograma rendimientos')

# Se ajustan los parámetros de una distribución
dist = 't'
params = getattr(st, dist).fit(ren.values) 

# Generación de la pdf de la distribución ajustado con los parámetros encontrados
curve_fit = getattr(st, dist).pdf(x, *params)
plt.plot(x, curve_fit, label='Distribución ajustada')
plt.legend()
plt.show()

# Q-Q
st.probplot(ren['NIO'], sparams=params[:-2], dist=dist, plot=plt);<jupyter_output><empty_output><jupyter_text>Valuación usando simulación: uso del histograma de rendimientos<jupyter_code>#cant de dias y escenarios
ndays = len(dates) 
nscen = 10
#prob de ocurrencia
prob = y/np.sum(y)
values = x[1:]
prob.sum()
#numeros aleatorios correspondientes a los rends
# Rendimientos simulados
ret = np.random.choice(values, ndays*nscen, p=prob)
# Fechas
dates = pd.date_range(start=Hoy,periods=ndays)
# Rendimien en Data Frame
sim_ret_hist = pd.DataFrame(ret.reshape((ndays,nscen)),index=dates)
sim_ret_hist
sim_closes_hist = (closes_nio.iloc[-1,0])*np.exp(sim_ret_hist.cumsum())
sim_closes_hist
sim_closes_hist.plot(figsize=(8,6),legend=False);
pd.concat([closes_nio,sim_closes_hist]).plot(figsize=(8,6),legend=False);
plt.title('Simulación usando el histograma de los rendimientos')
K = opcion_valuar['JSON']['strike']
ndays = len(dates)
nscen = 100000

# Histograma tomando la tasa libre de riesgo
freq, values = np.histogram(ret_nio+r-mu, bins=2000)
prob = freq/np.sum(freq)

# Simulación de los rendimientos
ret = np.random.choice(values[1:], ndays*nscen, p=prob)

# Simulación de precios
sim_ret_hist = pd.DataFrame(ret.reshape((ndays,nscen)),index=dates)
sim_closes_hist = (closes_nio.iloc[-1,0]) * np.exp(sim_ret_hist.cumsum())
strike = pd.DataFrame(K*np.ones(ndays*nscen).reshape((ndays,nscen)), index=dates)
put_hist = pd.DataFrame({'Prima':np.exp(-r*ndays) \
                          *np.fmax(strike-sim_closes_hist,np.zeros(ndays*nscen).reshape((ndays,nscen))).T.mean()}, index=dates)
put_hist.plot();
put_hist.iloc[-1]
opcion_valuar['JSON']
#confianza del 95%
confianza = 0.95
sigma_est = sim_closes_hist.iloc[-1].sem()
mean_est = put_hist.iloc[-1].Prima
i1 = st.t.interval(confianza,nscen-1, loc=mean_est, scale=sigma_est)
i2 = st.norm.interval(confianza, loc=mean_est, scale=sigma_est)
print(i1)<jupyter_output>(33.63454416549093, 34.61794052956814)
{'fraction_non_alphanumeric': 0.1322943722943723, 'fraction_numerical': 0.03186147186147186, 'mean_word_length': 6.099569760295021, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 37, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '642083', 'license': 'MIT', 'n_tokens_mistral': 4940, 'n_tokens_neox': 4643, 'n_words': 1007, 'path': 'Tarea9_AERodriguez_JACasta-o.ipynb', 'repo_name': 'Joseancg7/Tarea9_AERodriguez_JACasta-o', 'size': '11624'}