<jupyter_start><jupyter_text>Simulación de procesos financieros. **Nombres:** <NAME>, <NAME>**Fecha:** 07 de mayo de 2021.**Expediente** : if72622, if721861.**Profesor:** <NAME>. Tarea 10: Clase 23 [Liga al repositorio](https://github.com/PintorOD1997/ProyectoConjunto_LEspinosa_DPintor.git)  Enunciado de tarea  TareaImplementar el método de esquemas del trapecio, para valuar la opción call y put asiática con precio inicial, $S_0 = 100$, precio de ejercicio $K = 100$, tasa libre de riesgo $r = 0.10$, volatilidad $\sigma = 0.20$ y $T = 1$ año. Cuyo precio es $\approx 7.04$. Realizar la simulación en base a la siguiente tabla:![image.png](attachment:image.png)Observe que en esta tabla se encuentran los intervalos de confianza de la aproximación obtenida y además el tiempo de simulación que tarda en encontrar la respuesta cada método. - Se debe entonces realizar una simulación para la misma cantidad de trayectorias y número de pasos y construir una Dataframe de pandas para reportar todos los resultados obtenidos.**(70 puntos)**- Compare los resultados obtenidos con los resultados arrojados por la función `Riemann_approach`. Concluya. **(30 puntos)**  Solución Lyha Espinosa<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
from time import time
import matplotlib.pyplot as plt
import scipy.stats as st
import seaborn as sns; sns.set()
%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)
def BSprices(mu,sigma,S0,NbTraj,NbStep):
    """
    Expresión de la solución de la ecuación de Black-Scholes
    St = S0*exp((r-sigma^2/2)*t+ sigma*DeltaW)
    
    Parámetros
    ---------
    mu    : Tasa libre de riesgo
    sigma : Desviación estándar de los rendimientos
    S0    : Precio inicial del activo subyacente
    NbTraj: Cantidad de trayectorias a simular
    NbStep: Número de días a simular
    """
    # Datos para la fórmula de St
    nu = mu-(sigma**2)/2
    DeltaT = 1/NbStep
    SqDeltaT = np.sqrt(DeltaT)
    DeltaW = SqDeltaT*np.random.randn(NbTraj,NbStep-1)
    
    # Se obtiene --> Ln St = Ln S0+ nu*DeltaT + sigma*DeltaW
    increments = nu*DeltaT + sigma*DeltaW
    concat = np.concatenate((np.log(S0)*np.ones([NbTraj,1]),increments),axis=1)
    
    # Se utiliza cumsum por que se quiere simular los precios iniciando desde S0
    LogSt = np.cumsum(concat,axis=1)
    # Se obtienen los precios simulados para los NbStep fijados
    St = np.exp(LogSt)
    # Vector con la cantidad de días simulados
    t = np.arange(0,NbStep)

    return St.T,t

def calc_daily_ret(closes):
    return np.log(closes/closes.shift(1)).iloc[1:]<jupyter_output><empty_output><jupyter_text>Call<jupyter_code>def call_asiatica_trap(K:'Strike price',r:'Tasa libre de riesgo',S0:'Precio inicial',
                     NbTraj:'Número trayectorias',NbStep:'Cantidad de pasos a simular',
                     sigma:'Volatilidad',T:'Tiempo de cierre del contrato'):
    
    # Iniciar Tiempo
    tiempo_in = time()
    
    # precios mediante black and scholes
    St,t = BSprices(r,sigma,S0,NbTraj,NbStep)
    prices = pd.DataFrame(St,index=t) #DataFrame de precios
    
    # precios promedio
    h = T/NbStep
    Av_t = np.cumsum(prices * (2+r*h+np.random.randn(NbStep,NbTraj)*sigma))*h/(2*T)
    
    strike = K
    # Calculamos el call
    valuacion = pd.DataFrame({'Prima': np.exp(-r*T)*np.fmax(Av_t - strike, 0).mean(axis=1)}, index=t)
    
    # intervalos de confianza
    conf = 0.95
    i = st.norm.interval(conf, loc = valuacion.iloc[-1].Prima, scale = valuacion.sem().Prima)
    
    
    tiempo_fin = time()
    tiempo_total = tiempo_fin - tiempo_in
    
    # regresar prima, intervalos de confianza, rango de intervalos  y tiempo
    return np.array([valuacion.iloc[-1].Prima,i[0],i[1],i[1]-i[0],tiempo_total])

# Valores de la opcion 
S0 = 100
K = 100
r = 0.1
sigma = 0.2
T = 1

# Trayectorias monte carlo
NbTraj = [1000,5000,10000,50000,100000,500000,1000000]

# Pasos en el tiempo
NbStep = [10,50,100]
call = list(map(lambda trayectorias:list(map(lambda pasos: 
                                             call_asiatica_trap(K,r,S0,trayectorias,pasos,sigma,T),NbStep)), NbTraj))
n = 3 # niveles por index

# indice posicion de cada rango
i1 =list(map(lambda i: int(i/n),range(7*n)))

# posicion de cada sub rango
i2 =list(map(lambda i: int(i%n),range(7*n)))

# index del data frame
indx = pd.MultiIndex(levels=[NbTraj,NbStep], codes=[i1, i2])

call_array = np.array([call[i1[i]][i2[i]] for i in range(len(i1))])

call_aprox = np.array([i[0] for i in call_array]) # aproximacion

# limite inferior
lim_inf = np.array([i[1] for i in call_array])

# limite superior
lim_sup = np.array([i[2] for i in call_array])

# rango de limites 
rango = np.array([i[3] for i in call_array])

# obtener tiempos
tiempos_call = np.array([i[4] for i in call_array])


# General DF
tabla_call = pd.DataFrame(index=indx,columns=['Aproximacion','Linferior','Lsuperior','Longitud 95%','Tiempo'])
tabla_call.index.names = (['Tray. Monte Carlo','Num. pasos en el tiempo'])
tabla_call['Aproximacion'] = call_aprox
tabla_call['Linferior'] = lim_inf
tabla_call['Lsuperior'] = lim_sup
tabla_call['Longitud 95%'] = rango
tabla_call['Tiempo'] = np.round(tiempos_call,2)
pd.set_option("display.max_rows", None, "display.max_columns", None)
tabla_call<jupyter_output><empty_output><jupyter_text>Put<jupyter_code>def put_asiatica_trap(K:'Strike price',r:'Tasa libre de riesgo',S0:'Precio inicial',
                     NbTraj:'Número trayectorias',NbStep:'Cantidad de pasos a simular',
                     sigma:'Volatilidad',T:'Tiempo de cierre del contrato'):
    
    # Iniciar Tiempo
    tiempo_in = time()
    
    # precios mediante black and scholes
    St,t = BSprices(r,sigma,S0,NbTraj,NbStep)
    prices = pd.DataFrame(St,index=t) #DataFrame de precios
    
    # precios promedio
    h = T/NbStep
    Av_t = np.cumsum(prices * (2+r*h+np.random.randn(NbStep,NbTraj)*sigma))*h/(2*T)
    
    strike = K
    # Calculamos put
    valuacion = pd.DataFrame({'Prima': np.exp(-r*T)*np.fmax(strike - Av_t , 0).mean(axis=1)}, index=t)
    
    # intervalos de confianza
    conf = 0.95
    i = st.norm.interval(conf, loc = valuacion.iloc[-1].Prima, scale = valuacion.sem().Prima)
    
    
    tiempo_fin = time()
    tiempo_total = tiempo_fin - tiempo_in
    
    # regresar prima, intervalos de confianza, rango de intervalos  y tiempo
    return np.array([valuacion.iloc[-1].Prima,i[0],i[1],i[1]-i[0],tiempo_total])
put = list(map(lambda trayectorias:list(map(lambda pasos: 
                                             put_asiatica_trap(K,r,S0,trayectorias,pasos,sigma,T),NbStep)), NbTraj))
n = 3 # niveles por index

# indice posicion de cada rango
i1 =list(map(lambda i: int(i/n),range(7*n)))

# posicion de cada sub rango
i2 =list(map(lambda i: int(i%n),range(7*n)))

# index del data frame
indx = pd.MultiIndex(levels=[NbTraj,NbStep], codes=[i1, i2])

put_array = np.array([put[i1[i]][i2[i]] for i in range(len(i1))])

put_aprox = np.array([i[0] for i in put_array]) # aproximacion

# limite inferior
lim_inf_p = np.array([i[1] for i in put_array])

# limite superior
lim_sup_p = np.array([i[2] for i in put_array])

# rango de limites 
rango = np.array([i[3] for i in put_array])

# obtener tiempos
tiempos_put = np.array([i[4] for i in put_array])


# General DF
tabla_put = pd.DataFrame(index=indx,columns=['Aproximacion','Linferior','Lsuperior','Longitud 95%','Tiempo'])
tabla_put.index.names = (['Tray. Monte Carlo','Num. pasos en el tiempo'])
tabla_put['Aproximacion'] = put_aprox
tabla_put['Linferior'] = lim_inf_p
tabla_put['Lsuperior'] = lim_sup_p
tabla_put['Longitud 95%'] = rango
tabla_put['Tiempo'] = np.round(tiempos_put,2)
tabla_put<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1303692539562924, 'fraction_numerical': 0.024868123587038434, 'mean_word_length': 4.0462610899873255, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 17, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '502741', 'license': 'MIT', 'n_tokens_mistral': 3212, 'n_tokens_neox': 3100, 'n_words': 720, 'path': 'ProyectoConjunto_2_Tarea10_LEspinosa_DPintor.ipynb', 'repo_name': 'lyhaesp/ProyectoConjunto_LEspinosa_DPintor', 'size': '8011'}