Estoy tratando de realizar simulaciones de Monte Carlo utilizando números normales estándar cuasi aleatorios. Entiendo que podemos usar secuencias de Sobol para generar números uniformes, y luego usar la transformación integral de probabilidad para convertirlos en números normales estándar. Mi código da valores no realistas de la trayectoria de activos simulados:
import sobol_seq
import numpy as np
from scipy.stats import norm
def i4_sobol_generate_std_normal(dim_num, n, skip=1):
"""
Genera variables cuasi-aleatorias multivariadas estándar normales.
Parámetros:
Entrada, entero dim_num, la dimensión espacial.
Entrada, entero n, el número de puntos a generar.
Entrada, entero SKIP, el número de puntos iniciales a omitir.
Salida, np array real de forma (n, dim_num).
"""
sobols = sobol_seq.i4_sobol_generate(dim_num, n, skip)
normals = norm.ppf(sobols)
return normals
def GBM(Ttm, TradingDaysInAYear, NoOfPaths, UnderlyingPrice, RiskFreeRate, Volatility):
dt = float(Ttm) / TradingDaysInAYear
paths = np.zeros((TradingDaysInAYear + 1, NoOfPaths), np.float64)
paths[0] = UnderlyingPrice
for t in range(1, TradingDaysInAYear + 1):
rand = i4_sobol_generate_std_normal(1, NoOfPaths)
lRand = []
for i in range(len(rand)):
a = rand[i][0]
lRand.append(a)
rand = np.array(lRand)
paths[t] = paths[t - 1] * np.exp((RiskFreeRate - 0.5 * Volatility ** 2) * dt + Volatility * np.sqrt(dt) * rand)
return paths
GBM(1, 252, 8, 100., 0.05, 0.5)
array([[1.00000000e+02, 1.00000000e+02, 1.00000000e+02, ...,
1.00000000e+02, 1.00000000e+02, 1.00000000e+02],
[9.99702425e+01, 1.02116774e+02, 9.78688323e+01, ...,
1.00978615e+02, 9.64128959e+01, 9.72154915e+01],
[9.99404939e+01, 1.04278354e+02, 9.57830834e+01, ...,
1.01966807e+02, 9.29544649e+01, 9.45085180e+01],
...,
[9.28295879e+01, 1.88049044e+04, 4.58249200e-01, ...,
1.14117599e+03, 1.08089096e-02, 8.58754653e-02],
[9.28019642e+01, 1.92029616e+04, 4.48483141e-01, ...,
1.15234371e+03, 1.04211828e-02, 8.34842557e-02],
[9.27743486e+01, 1.96094448e+04, 4.38925214e-01, ...,
1.16362072e+03, 1.00473641e-02, 8.11596295e-02]])
Valores como 8.11596295e-02 no deberían generarse, por lo que creo que hay algo mal en el código.
Referencias: https://stats.stackexchange.com/questions/27450/best-method-for-transforming-low-discrepancy-sequence-into-normal-distribution, https://stackoverflow.com/questions/9412339/recommendations-for-low-discrepancy-e-g-sobol-quasi-random-sequences-in-pytho, https://github.com/naught101/sobol_seq
Se agradece cualquier ayuda.
0 votos
¿Qué es una implementación "simple"? ¿Qué encontraste y por qué no está bien? ¿Implementación en pseudo-código o en qué lenguaje?
0 votos
@gg: He editado la publicación para incluir los trabajos
1 votos
Entonces, ¿tal vez "sobol_seq.i4_sobol_generate" está incorrecto? ¿Qué hiciste para probar la corrección? ¿Y cómo podemos ver en tu código que "8.11596295e-02 no debería generarse"?
1 votos
Parece que estás generando 1d números sobol para cada paso de tiempo. La secuencia de sobol es determinista, lo que significa que los números que estás utilizando para cada paso de tiempo son los mismos, por lo que esperaría que tus caminos divergieran en ambas direcciones y se dispersaran (exponencialmente). Necesitas considerar cada paso de tiempo como una dimensión diferente al generar la secuencia, y luego usar una rebanada diferente para cada paso de tiempo.
0 votos
Por favor, proporcione en su respuesta la última fila de su matriz de caminos, creo que encontrará que tiene tanto números muy pequeños como muy grandes. Además, si representara cada camino (por lo tanto, cada columna) frente al tiempo, verá que todas las líneas son suaves, no se cruzan entre sí y se alejan de 100 (derivando en r).