Monte Carlo
por dentro

Un simulador que dibuja 10.000 futuros posibles de una acción y luego se examina a sí mismo: ¿sus «90%» se cumplen el 90% de las veces? Con SPY, el modelo de libro dice 50% y acierta el 73%.

5 ficheros · ~780 líneas · 16 acciones validadas · leído el 04/10/2026

  1. Una fábrica de futuros con inspectorlas piezas
  2. La campana no tapa las colaspor qué la bolsa no es normal
  3. El bombo de la campanamotor 1: GBM
  4. Tijeras y películamotor 2: bootstrap por bloques
  5. Una chincheta donde cayó la realidadel examen: PIT y cobertura
  6. Lo que pasa cuando escribes «Apple»un viaje por el código
  7. Las notas en 16 accionesKupiec y Kolmogorov–Smirnov
  8. Ocho peldaños, dos rotoscómo se construyó
  9. El cuadro de fusiblesdónde tocar si se rompe
LÁMINA 01 · PIEZAS

Una fábrica de futuros con inspector

Entra una cinta con 20 años de precios, dos motores la convierten en 10.000 futuros posibles y una lupa comprueba si esos futuros dijeron la verdad.

333,7 · 331,2 · 340,8 GBM bloques 20 años de precios dos motores 10.000 futuros ¿cumple lo prometido? analyze() · montecarlo.py:206

En cristiano

Escribes «Apple». El programa baja 20 años de precios de Yahoo y mide cuánto se mueve la acción. Con eso fabrica 10.000 futuros a 3 meses de dos maneras distintas.

Lo que lo hace distinto de los cientos de repos iguales: al final se examina a sí mismo contra 15 años de fechas reales.

En el dibujoQué haceDónde
cinta de preciosbaja el histórico ajustado y elige la bolsa que más mueve (resolución por nombre)montecarlo.py:99
engranaje GBMinventa días con una campana normal (movimiento browniano geométrico)montecarlo.py:48
engranaje bloquescopia meses reales del pasado en otro orden (bootstrap por bloques)montecarlo.py:52
abanico10.000 caminos → franjas, VaR, Expected Shortfallmontecarlo.py:147
lupael examen: ¿se cumplen sus «90%»? (backtest de calibración)montecarlo.py:182
ventanillaservidor sin dependencias que entrega todo en un JSONserver.py:31

Dato real: Apple a 3 meses desde 333,69 USD: 6 de cada 10 futuros acaban en verde (64,0% con bootstrap, 62,1% con GBM).

LÁMINA 02 · ETAPA · LOS DATOS

La campana no tapa las colas

El bichito baja una campana de cristal (la distribución normal) sobre un montón de días reales: los tranquilos caben, pero los días extremos se quedan fuera, en rojo.

la campana días tranquilos colas gordas 38 días vs 0,3 fat_tails() · montecarlo.py:127

En cristiano

Si los días de bolsa siguieran una campana, un día de más de 4 desviaciones (±4σ) pasaría unas 0,3 veces en 20 años de SPY. Pasó 38 veces.

Y el centro es más estrecho de lo que dice la campana: muchos días aburridos y unos pocos brutales. Eso se mide con la curtosis: 0 en una campana y 14,1 en SPY.

En el dibujoQué haceDónde
montón de díashistograma de rendimientos diarios en log, en desviaciones (z)montecarlo.py:132
campana de cristallo que esperaría una normal con la misma σmontecarlo.py:135
bloques rojosdías de más de ±4σ: reales frente a esperados (2·Φ(−4)·n)montecarlo.py:139
la gráfica en la webbarras reales frente a curva normal, en escala logdocs/demo/index.html:251

Dato real: SPY 2006-2026: 38 días por encima de ±4σ, cuando la campana esperaría 0,32. Curtosis en exceso 14,1. Peor día de Apple: −17,9%.

LÁMINA 03 · ETAPA · MOTOR 1

El bombo de la campana

El bichito gira un bombo de lotería cuyas bolas salen de una campana N(μ, σ). Cada bola es un día; 63 bolas seguidas son un futuro de 3 meses.

N(μ, σ) una bola = un día ×10.000 sim_gbm() · montecarlo.py:48

En cristiano

Toma los últimos 5 años (1.260 días). Mide la subida media diaria y lo que se mueve: μ = 20,8% y σ = 27,9% al año en Apple. Luego sortea cada día de una campana con esos dos números.

Es la fórmula del libro, ST = S0·exp((μ − σ²/2)T + σ√T·Z), la misma que hay debajo de Black–Scholes. Se puede comprobar con lápiz, y por eso es la primera prueba de que el código está bien.

En el dibujoQué haceDónde
bombosortea 10.000 × 63 rendimientos de N(media, desviación)montecarlo.py:48
camino de bolassuma acumulada de logs → precio (exp de la suma)montecarlo.py:169
lápiz y papeltest: simulado frente a fórmula cerrada lognormaltest_montecarlo.py:38
la fórmula en la webKaTeX con los números reales de la accióndocs/demo/index.html:273

Dato real: Apple 3m, P(ganar): 62,05% simulado frente a 61,89% exacto; el azar de 10.000 caminos permite ±0,95 puntos. VaR 95%: 17,0% frente a 17,1%.

LÁMINA 04 · ETAPA · MOTOR 2

Tijeras y película: el futuro hecho de pasado

El bichito corta trozos de 21 días de la película real de los últimos años y los empalma en otro orden: un futuro nuevo hecho con días que sí pasaron.

5 años reales un crash real trozos de 21 días un futuro nuevo sim_bootstrap() · montecarlo.py:52

En cristiano

Este motor no supone ninguna campana: sortea meses enteros reales (bloques de 21 días) de los últimos 5 años y los pega uno detrás de otro.

¿Por qué bloques y no días sueltos? Los días malos vienen en racimo: tras un crash suele venir otro día malo (agrupamiento de volatilidad). Con un mes entero, el racimo sobrevive.

En el dibujoQué haceDónde
tira de películarendimientos diarios en log de la ventana de calibraciónmontecarlo.py:212
tijerasinicio aleatorio de cada bloque (np.random.integers)montecarlo.py:54
empalmeíndices bloque a bloque, recortados a los días del horizontemontecarlo.py:55
testcomprueba que solo usa días reales y la longitud pedidatest_montecarlo.py:19

Dato real: Apple 3m, Expected Shortfall 95%: 20,1% con bootstrap frente a 21,8% con GBM. Probabilidad de ganar con 5 semillas distintas: entre 63,1% y 64,3%.

LÁMINA 05 · ETAPA · EL EXAMEN

Una chincheta donde cayó la realidad

En cada fecha del pasado, el simulador hace su abanico. El bichito clava una chincheta en el punto de ese abanico donde cayó el precio real, y luego se cuenta cuántas chinchetas quedaron dentro de la franja prometida.

100% 0% franja del 90% aquí cayó la realidad 177 fechas dentro fuera exam() · montecarlo.py:182

En cristiano

Es como juzgar al hombre del tiempo: no por un día, sino por si llueve el 70% de las veces que dice «70%».

En cada fecha (una por mes desde 2011) el simulador solo ve los 5 años anteriores. Se mira qué fracción de sus caminos quedó por debajo del precio real: es el PIT (probability integral transform). Si el modelo es honesto, los PIT salen repartidos por igual entre 0 y 1.

En el dibujoQué haceDónde
regla 0-100%el abanico de esa fecha, ordenado de peor a mejormontecarlo.py:188
chincheta (GBM)PIT exacto con la normal, sin simularmontecarlo.py:191
chincheta (bootstrap)PIT con 2.000 caminos por fechamontecarlo.py:192
hoja de recuentocobertura: % de PIT dentro de cada franjamontecarlo.py:199
calendariosfechas que se pisan → pruebas independientes = fechas·21/díasmontecarlo.py:194

Dato real: Apple 3m: 177 fechas, equivalentes a 59 pruebas independientes. Franja del 90%: GBM 94,4%, bootstrap 93,2%, y las dos caben en el margen de suerte de ±7,6 puntos.

LÁMINA 06 · VIAJE

Lo que pasa cuando escribes «Apple»

El bichito lleva un sobre con «Apple» por un camino de cinco paradas, desde la caja de texto hasta los seis pasos que se pintan en pantalla.

1 · escribes Apple 2 · /api/sim 3 · elige AAPL 4 · caminos + examen 6 de 10 index.html:385 montecarlo.py:99

En cristiano

Pulsas «Simular». La web llama al servidor, que busca la empresa por su nombre y elige la cotización que más dinero mueve. Calcula los dos motores y el examen y lo devuelve todo de una vez. Tarda unos 4 segundos.

En el dibujoQué haceDónde
1 · portátillee el texto y el horizonte y llama al servidor (fetch)docs/demo/index.html:377
2 · buzónservidor stdlib: /api/sim → analyze()server.py:31
3 · lupaYahoo → candidatos → el más negociado con datos limpiosmontecarlo.py:117
4 · engranajessimulate() con los dos motores + exam()montecarlo.py:165
5 · cartelpinta el titular, el cono, las cifras y el examendocs/demo/index.html:370

Dato real: «Inditex» no devuelve ITX.MC en Yahoo: se resuelve a IXD1.DE (Xetra, mismos euros). El ticker exacto ITX.MC se respeta.

LÁMINA 07 · DATOS · LA PRUEBA

Las notas en 16 acciones

El bichito levanta los dos boletines tras examinar a los motores en 16 acciones con los tests que usa un banco: la campana suspende la forma en la mitad y el bootstrap aprueba en todas.

GBM forma: 8/16 ✗ «50%» → 62% Bootstrap forma: 0/16 ✓ «50%» → 52% Kupiec + Kolmogorov–Smirnov

En cristiano

Para no elegir 4 acciones que salgan bien, el examen se repite en 16: EE. UU., España, Reino Unido y ETFs, a 1 mes. Hay dos pruebas formales:

Kupiec (la de Basilea) cuenta las roturas del VaR 95%. Kolmogorov–Smirnov mira si los PIT están repartidos por igual, o sea, si acierta la forma entera. El GBM casi siempre pasa Kupiec, pero suspende KS en 8 de 16: mirando solo el VaR, no ves el fallo.

En el dibujoQué haceDónde
boletín GBMfranja del 50% → 61,9%; roturas del VaR 95% → 3,5%validar.py:21
boletín bootstrapfranja del 50% → 51,6%; roturas → 4,9%validar.py:21
Kupiec + KSchi² con 1 g.l. sobre roturas; KS frente a la uniformevalidar.py:28
la diagonal en la webcurva prometido-vs-real + margen binomialdocs/demo/index.html:338

Dato real: SPY a 1 mes, 179 pruebas: el GBM dice 50% y acierta el 73,2%; el bootstrap, el 53,6%. El margen de suerte es de ±7,3 puntos: el fallo del GBM no es casualidad.

LÁMINA 08 · HISTORIA

Ocho peldaños, dos rotos

El proyecto se construyó en un día. El bichito sube la escalera y se para delante del peldaño roto: dos veces algo parecía bien y no lo estaba.

reel nº 2 «cliché» el plan test 90% ✓ Hannover 73 vs 54 frase de más 16 acciones

En cristiano

Salió del reel de @quant.with.isamu (nº 2 de 15). Tus otros vídeos avisaban de que es un proyecto cliché, así que la idea fue añadir el examen.

Hubo dos tropiezos de verdad. «Inditex» se resolvía a la bolsa de Hannover, con precios rotos (curtosis de 1.301): se arregló con un filtro de calidad. Y algunas frases de la web afirmaban más de lo que da la muestra: se arreglaron con el margen binomial.

En el dibujoQué haceDónde
peldaño 4examen sobre datos que sí son campana → ≈90%test_montecarlo.py:23
peldaño 5 (roto)Hannover: días congelados o saltos imposibles → se descarta la bolsamontecarlo.py:78
peldaño 7 (roto)«exagera el riesgo» con 59 pruebas → margen ±7,6docs/demo/index.html:338
peldaño 8validación en 16 acciones con Kupiec y KSvalidar.py:14

Dato real: Inditex en IXD1.HA (Hannover): curtosis 1.301,7. En ITX.MC (Madrid): 15,5. Misma empresa, datos de otra bolsa.

LÁMINA 09 · AVERÍAS

El cuadro de fusibles

Cuando algo falla, el bichito abre el cuadro y mira con la lupa qué fusible saltó. Cada fusible es un síntoma con su sitio en el código.

no laencuentra tardamucho puertoocupado Yahoocambia cifrasraras

En cristiano

Cada fallo probable viene con la pista de dónde mirar. El más traicionero es «cifras raras»: no da ningún error, solo números absurdos, como una curtosis de 1.301 o un VaR enorme. Casi siempre es una bolsa secundaria con datos rotos.

En el dibujoQué haceDónde
no la encuentraYahoo no devuelve la bolsa principal → usa el ticker exacto (ITX.MC)montecarlo.py:99
tarda muchoel examen bootstrap: 2.000 caminos × ~180 fechas → bajar N_EXAMmontecarlo.py:32
puerto ocupado8000 lo usa otra app → PORT=8005server.py:47
Yahoo cambiayfinance cambia columnas o límites → todo pasa por load()montecarlo.py:66
cifras rarasfiltro: >10% de días sin cambio o salto >70% → se descartamontecarlo.py:78

Dato real: Un aviso que no es error: los 404 de yfinance al probar «APPLE» como ticker. Se silencian en montecarlo.py:59 porque son parte de la búsqueda.

Un modelo no es bueno porque acierte una vez:
es bueno si sus «90%» se cumplen el 90% de las veces.