Método de Monte Carlo · Tema 37

Problemas financieros

Precio justo como promedio descontado: la call es max(S−K,0) promediado.

01 · Punto de partida

Una opción es una esperanza

Una call paga max(S−K, 0) al vencimiento. Si S terminal es lognormal, el precio justo es e^(−rT)·E[max(S−K,0)]. Sin fórmula a mano: se sortean S, se promedia el pago y se descuenta.

El mismo motor da cartera, VaR y probabilidad de ejercer.

  • ¿Qué distribución tiene S terminal?
  • ¿Cuál es el pago por réplica?
  • ¿Con qué tasa descuento?
  • ¿Qué N estabiliza el precio?

02 · Definición

Tres salidas financieras

💲

Precio

Pago medio descontado: lo que vale hoy la apuesta.

🎯

P(ejercer)

Fracción con S > K: cuántas veces la opción paga algo.

⚠️

VaR cartera

Percentil 5 del valor final: cuánto puedo perder.

Call S₀ = 100, r = 5%, T = 1, σ = 20%.
KPrecio ≈P(ejercer)
90~16,7~72%
100~10,4~56%
110~6,0~40%

03 · Método

S terminal→Pago→Descontar
  1. 1
    Sortear S.

    Z ~ N(0,1) y S = S₀·exp((r−σ²/2)T + σ√T·Z).

  2. 2
    Calcular pago.

    max(S−K, 0): cero si no se ejerce.

  3. 3
    Descontar y promediar.

    Precio = e^(−rT)·media ± e^(−rT)·s/√N.

Riesgo neutro
Se usa r como deriva para preciar (no la real μ): convención de no arbitraje.
σ (volatilidad)
Manda el precio: más σ = más chance de S alto = call más cara.
N grande
Pagos con muchos ceros piden N ≥ 20 000 para estabilizar.

04 · Ejemplos

  1. 1
    Call K = 100.

    ~10,4 con σ = 20%. Sube a ~14 con σ = 30%.

  2. 2
    Cartera 60/40.

    R = 0,6·R₁ + 0,4·R₂: media y VaR del mix.

  3. 3
    Seguro.

    Prima = E[pago] + recargo: la misma esperanza con otro nombre.

05 · Representación en Python

Call en 10 líneas

Python en tu navegador. Cambiá K y σ: el precio se mueve solo.

import random
import math

def precio_call(S0=100, K=100, r=0.05, sigma=0.2, T=1, N=20000):
    tot = 0
    ejerce = 0
    for _ in range(N):
        z = random.gauss(0, 1)
        S = S0*math.exp((r-0.5*sigma**2)*T + sigma*math.sqrt(T)*z)
        pago = max(S-K, 0)
        tot += pago
        if pago > 0:
            ejerce += 1
    return math.exp(-r*T)*tot/N, ejerce/N

precio, p = precio_call()
print(f"precio {precio:.2f} P(ejercer) {p:.2f}")

06 · Exploración

Laboratorio: K y σ mueven el precio

Histograma de S terminal (S₀ = 100). La amarilla es K: solo lo de la derecha paga. Subí σ y la cola gorda encarece.

EXPERIMENTO 37

La call a ojo

precio = e^(−rT)·media(max(S−K,0))

Los resultados numéricos aparecen debajo.
Precio—
P(ejercer)—
Error ±—
Lectura—

Tocá «Preciar» con N = 12 000.

Barras verdes a la derecha de K pagan; grises no. Más σ ensancha y encarece aunque la media de S sea parecida.

Preguntas para explorar

  1. Con K = 80, ¿P(ejercer) supera 80%? ¿Y con K = 120?
  2. Con σ = 0,4, ¿el precio sube o baja vs σ = 0,15?
  3. ¿Por qué la call nunca vale menos que S₀ − K·e^(−rT)?
Ver respuestas sugeridas
  1. Sí: ~90% vs ~25%. K manda la probabilidad.
  2. Sube: más cola derecha = más pagos grandes. Volatilidad = valor para el comprador.
  3. Arbitraje: si valiera menos, compro call + vendo spot y gano seguro.

07 · Comprensión

Confusiones frecuentes

«Precio = promedio de S menos K»

No: promedio de max(S−K,0). Los ceros cuentan: sin max se sobrevalúa.

«Uso μ real en vez de r»

Para preciar se usa r (riesgo neutro). Con μ sale el retorno esperado, no el precio.

«Olvido descontar»

Sin e^(−rT) vale de más 5% con r = 5%. El dinero futuro vale menos.

«N = 1 000 alcanza»

Con 40% de ceros, el error es grande. N ≥ 15 000 para ±0,2.

08 · Práctica guiada

Ejercicios con Python

Ejercicio 1: call base

Preciá K = 100, σ = 0,2 con N = 15 000.

import random
import math

S0, K, r, sigma, N = 100, 100, 0.05, 0.2, 15000
tot = 0
for _ in range(N):
    S = S0*math.exp((r-0.5*sigma**2) + sigma*random.gauss(0,1))
    tot += max(S-K, 0)
print(round(math.exp(-r)*tot/N, 2))
Ver solución razonada

~10,4 ± 0,2. Referencia Black-Scholes: 10,45. Motor validado.

Ejercicio 2: subir σ

Repetí con σ = 0,4. ¿Cuánto sube?

import random
import math

def precio(sigma):
    tot = sum(max(100*math.exp((0.05-0.5*sigma**2)+sigma*random.gauss(0,1))-100, 0) for _ in range(12000))
    return math.exp(-0.05)*tot/12000

print(round(precio(0.2), 2), round(precio(0.4), 2))
Ver solución

~10,4 → ~18,0. La volatilidad casi duplica la call.

Ejercicio 3: cartera 60/40

R₁ ~ N(0,08, 0,15), R₂ ~ N(0,03, 0,05). Estimá media y VaR₅ del mix.

Ver una posible respuesta
import random

N = 15000
rs = sorted(0.6*random.gauss(0.08, 0.15)+0.4*random.gauss(0.03, 0.05) for _ in range(N))
print(round(sum(rs)/N, 4), round(rs[int(0.05*N)], 4))

Media ~0,06, VaR₅ ~−0,10: se gana 6% esperando perder 10% 1 de cada 20.

09 · Síntesis

Ideas para recordar

  • Call = e^(−rT)·E[max(S−K,0)] con S lognormal.
  • Sortear Z, armar S, max, promediar, descontar.
  • σ manda el precio; K manda P(ejercer).
  • N ≥ 15 000 por los ceros; siempre con error.
  • El motor vale para exóticas donde no hay fórmula.

En el próximo tema stockearemos bajo azar: la simulación de inventarios.