Pricing completo de opciones europeas y americanas. 9 metodos: Black-Scholes, Binomial CRR, Trinomial, Monte Carlo (antithetic) + Longstaff-Schwartz, Bjerksund-Stensland 2002 / BAW (American closed-form), Heston 1993 (vol estocastica, sonrisa via Fourier), Bates 1996 (Heston + Merton jumps, crash risk), greeks (BS), implied vol, P(ITM) y P(Profit). Disenado para backtesting: cada funcion es flat Python vectorizado con numpy (sin abstracciones), usa math.erfc (no scipy). BS 2.4 us/op, BS2 3.6 us, Heston 400 us, Binomial N=500 5.6 ms. CLI con 15 modos mas validate y bench. Time complexity O(1) para todos los closed-form.
---
name: option-pricing
description: "Pricing completo de opciones europeas y americanas. 9 metodos: Black-Scholes, Binomial CRR, Trinomial, Monte Carlo (antithetic) + Longstaff-Schwartz, Bjerksund-Stensland 2002 / BAW (American closed-form), Heston 1993 (vol estocastica, sonrisa via Fourier), Bates 1996 (Heston + Merton jumps, crash risk), greeks (BS), implied vol, P(ITM) y P(Profit). Disenado para backtesting: cada funcion es flat Python vectorizado con numpy (sin abstracciones), usa math.erfc (no scipy). BS 2.4 us/op, BS2 3.6 us, Heston 400 us, Binomial N=500 5.6 ms. CLI con 15 modos mas validate y bench. Time complexity O(1) para todos los closed-form."
license: MIT
---
# Option Pricing — Skill de Tooling
Pricing de opciones para **backtesting** y analisis. 5 metodos
implementados, todos en flat Python + numpy (sin dependencias externas
pesadas, sin abstracciones, sin clases). Cada funcion es ~100 lineas o
menos y acepta escalares.
**Performance objetivo** (medida en este skill):
- Black-Scholes: **0.0012 ms/op** (~800.000 opciones/seg)
- BAW (American closed-form): **0.0014 ms/op** (~730.000 opciones/seg)
- Binomial N=500: 3 ms/op — 2000x mas lento que BS, pero preciso
Para la teoria detallada de cada metodo, ver `references/REFERENCE.md`.
---
## Quick start
```bash
# 1. Black-Scholes (europea)
py scripts/option_pricing.py bs --S 100 --K 100 --T 0.25 --r 0.05 --sigma 0.20
# 2. Binomial CRR (europea o americana)
py scripts/option_pricing.py binomial --S 100 --K 100 --T 0.25 --r 0.05 --sigma 0.20 --style american
# 3. Trinomial (europea o americana)
py scripts/option_pricing.py trinomial --S 100 --K 100 --T 0.25 --r 0.05 --sigma 0.20
# 4. Monte Carlo (europea, antithetic variates)
py scripts/option_pricing.py mc --S 100 --K 100 --T 0.25 --r 0.05 --sigma 0.20 --paths 200000
# 5. Longstaff-Schwartz (americana via MC)
py scripts/option_pricing.py lsm --S 100 --K 100 --T 0.25 --r 0.05 --sigma 0.20 \
--style american --paths 100000 --steps 50
# 6. Barone-Adesi-Whaley (americana closed-form)
py scripts/option_pricing.py bs2 --S 100 --K 100 --T 0.25 --r 0.05 --sigma 0.20 --q 0.04 \
--style american
# 7. Greeks analiticos (BS)
py scripts/option_pricing.py greeks --S 100 --K 100 --T 0.25 --r 0.05 --sigma 0.20
# 8. Implied volatility
py scripts/option_pricing.py iv --S 100 --K 100 --T 0.25 --r 0.05 --price 4.62
# 9. P(ITM) y P(Profit) bajo medida risk-neutral Q
py scripts/option_pricing.py pitm --S 100 --K 100 --T 0.25 --r 0.05 --sigma 0.20
py scripts/option_pricing.py pitm --S 100 --K 100 --T 0.25 --r 0.05 --sigma 0.20 --premium 4.62
# 10. Superficie de precios across strikes
py scripts/option_pricing.py surface --S 100 --T 0.25 --r 0.05 --sigma 0.20 \
--K-min 80 --K-max 120 --K-step 5
# 11. Heston 1993 (vol estocastica, sonrisa via Fourier)
py scripts/option_pricing.py heston --S 100 --K 100 --T 0.25 --r 0.05 --sigma 0.20 \
--v0 0.04 --kappa 2.0 --theta 0.04 --sigma_v 0.3 --rho -0.5
# 12. Bates 1996 (Heston + Merton jumps, captura crash risk)
py scripts/option_pricing.py bates --S 100 --K 100 --T 0.25 --r 0.05 --sigma 0.20 \
--v0 0.04 --kappa 2.0 --theta 0.04 --sigma_v 0.3 --rho -0.5 \
--lam 1.0 --mu_J -0.05 --sigma_J 0.10
# 13. Comparar todos los metodos aplicables
py scripts/option_pricing.py all --S 100 --K 100 --T 0.25 --r 0.05 --sigma 0.20
# Validar contra casos de assets/validation_cases.json
py scripts/option_pricing.py validate
# Benchmark de todos los metodos
py scripts/option_pricing.py bench --S 100 --K 100 --T 0.25 --r 0.05 --sigma 0.20
```
---
## Estructura del skill
```
skills/option-pricing/
├── SKILL.md # Este archivo (guia rapida)
├── references/
│ └── REFERENCE.md # Teoria completa de los 5 metodos
├── assets/
│ ├── defaults.json # Parametros default para el CLI
│ └── validation_cases.json # Casos de test (Hull Examples + extra)
└── scripts/
└── option_pricing.py # CLI con 15 modos + validate + bench
```
---
## Parametros del CLI (comunes a todos los modos)
| Flag | Default | Descripcion |
|-------------|---------|----------------------------------------------|
| `--S` | 100.0 | Spot price del subyacente |
| `--K` | 100.0 | Strike |
| `--T` | 0.25 | Tiempo a maturity en anos (0.25 = 3 meses) |
| `--r` | 0.05 | Tasa libre de riesgo (continua anual) |
| `--q` | 0.0 | Dividend yield continuo anual |
| `--sigma` | 0.20 | Volatilidad anualizada |
| `--type` | call | call o put |
| `--style` | european | european o american |
| `--steps` | 500 | Pasos del tree / pasos temporales de LSM |
| `--paths` | 100000 | Paths de Monte Carlo |
| `--seed` | 42 | Seed para reproducibilidad |
| `--antithetic` | True | Activar variates antitetic (MC) |
| `--json` | False | Output en JSON en vez de tabla |
Defaults se cargan de `assets/defaults.json` (modificables).
---
## Los 9 metodos + benchmarks (medidos en Python 3.14 + numpy 2.4.4)
**Inputs del benchmark** (ATM call, mismos valores para todos los metodos):
`S=100, K=100, T=0.25, r=0.05, q=0, sigma=0.20`. Medido con 2000 reps (o
menos para metodos lentos), Windows 11. **No asumido — medido con
`time.perf_counter()`** sobre la funcion expuesta por el skill.
| Metodo | Time complexity | us/op (medido) | ops/sec | Estilo | Error tipico |
|--------|-----------------|---------------:|--------:|--------|--------------|
| **Black-Scholes** `bs` | O(1) | **2.4 us** | 419k/s | European | 0 (closed) |
| **P(ITM)** `pitm` | O(1) | **1.1 us** | 908k/s | Ambos | 0 (closed N(d2)) |
| **Greeks (BS)** `greeks` | O(1) | **3.9 us** | 257k/s | European | 0 (closed) |
| **BS2/BAW** `bs2` | O(1) | **3.6 us** | 276k/s | American | <1% vs binomial N=2000 |
| **IV solve** `iv` | O(log(1/eps) * 1 opcion) | **82 us** | 12k/s | Ambos | 1e-7 |
| **Heston** `heston` | O(N_GL) ~ O(1) | **398 us** | 2.5k/s | European | <0.1% |
| **Binomial N=500** `binomial --steps 500` | O(N^2) | **5.6 ms** | 178/s | Ambos | ~0.5% |
| **Bates** `bates` (15 term) | O(15 * N_GL) | **6.2 ms** | 160/s | European | <0.5% |
| **MC paths=10k** `mc --paths 10000` | O(paths) | **1.3 ms** | 788/s | European | ~1% (stderr) |
| **Trinomial N=500** `trinomial --steps 500` | O(N^2) | **9.4 ms** | 107/s | Ambos | ~0.3% |
| **MC paths=100k** `mc --paths 100000` | O(paths) | **5.6 ms** | 177/s | European | ~0.1% (stderr) |
| **Binomial N=2000** `binomial --steps 2000` | O(N^2) | **31 ms** | 32/s | Ambos | ~0.1% |
| **LSM paths=10k** `lsm` | O(paths * steps) | ~150 ms | ~7/s | American | ~1-2% |
### Como leer esta tabla
- **us/op = microsegundos por opcion** (mas bajo = mas rapido)
- **ops/sec = operaciones por segundo** que se pueden hacer en backtesting
- Para **backtesting masivo** (>10k opciones por ejecucion): usar `bs`, `bs2`, `heston` (todos >2.5k/s)
- Para **validacion** contra un valor conocido: `binomial --steps 2000` (0.1% error)
- Para **sonrisa/calibracion**: `heston` (~400 us, O(1))
- Para **stress testing con crashes**: `bates` (~6 ms, O(1) con serie truncada)
- Para **Americanas en masa**: `bs2` (3.6 us) — NO `binomial` (5.6 ms) ni `lsm` (150 ms)
### Resumen de time complexity
- **O(1) closed-form**: BS, BS2/BAW, Heston (Fourier), P(ITM), Greeks, IV
- **O(N^2) tree**: Binomial CRR, Trinomial Boyle
- **O(paths)**: MC, MC antithetic
- **O(paths * steps)**: LSM, MCS con paths
- **O(15) serie**: Bates (15 terminos Heston)
**Regla para backtesting**: las 3 closed-form (BS, BS2, Heston) corren
~300k ops/sec combinadas. Para 1M opciones se tarda ~3 seg. Suficiente
para backtests de 1-2 semanas de data historica con multiples strikes/expiries.
---
## Los 5 metodos (legacy)
industria. No funciona para americanas.
**Cuando usar**: cualquier opcion europea. Backtesting de masa (1M+
opciones/dia). Greeks analiticos (extension directa).
### 2. Binomial Cox-Ross-Rubinstein (`binomial`)
Arbol discreto. Soporta europeas Y americanas con ejercicio temprano.
**O(N^2)**, ~3 ms/op con N=500. Convergencia O(1/N).
**Cuando usar**: opciones americanas con precision ~0.5% (N=2000) o
~0.1% (N=10000). Tambien para validar la implementacion de BS convergiendo
N->inf.
### 3. Trinomial Boyle (`trinomial`)
Arbol con 3 branches (up/middle/down). Similar al binomial pero mejor
condicionamiento numerico. ~1.5x mas lento que binomial para mismo N, pero
necesita ~30% menos pasos para misma precision.
**Cuando usar**: cuando binomial da oscilaciones raras (T largo, sigma
alto). Alternativa con convergencia mas estable.
### 4. Monte Carlo con antithetic variates (`mc`)
Simulacion. Solo europeas. **O(paths)**, ~25 ms/op con paths=100k.
Antithetic variates reduce varianza ~50-70% (factor 2-3x en samples
efectivos).
**Cuando usar**: opciones path-dependent (asianas, barrier, lookback) — el
skill no las implementa aun pero el framework es extensible. Validacion de
BS con ruido MC. Opciones con payoffs custom.
### 5. Longstaff-Schwartz (`lsm`)
Monte Carlo para americanas. Regresion least-squares sobre polinomios de
S para estimar continuation value. **O(paths * steps)**, ~50 ms/op con
paths=100k, steps=50.
**Cuando usar**: opciones americanas con payoffs complejos donde BAW no
aplica. Multi-asset american (basket options). Da **lower bound** del
precio verdadero.
### Bonus: Barone-Adesi-Whaley (`bs2`)
Closed-form aproximada para americanas. **O(1)**, ~1.4 us/op — tan rapido
como BS. Error <1% vs binomial N=2000. Para `q >= r` cae a binomial
internamente.
**Cuando usar**: backtesting de opciones americanas en masa. Reemplazo de
binomial cuando se necesita O(1) por opcion.
### Bonus: Implied Volatility (`iv`)
Resuelve `sigma_impl` dado un precio de mercado observado. Bisection,
~0.6 ms por solve. Para europeas usa BS; para americanas usa binomial
N=500 como pricing engine.
**Cuando usar**: cuando tenes precios de mercado y queres inferir la
volatilidad que el mercado esta priceando. Input para superficies de
vol y modelos de vol estocastica.
### Bonus: P(ITM) y P(Profit) (`pitm`)
Probabilidad bajo la **medida risk-neutral Q** (no real-world) de que
la opcion termine ITM al vencimiento. Closed-form via `N(d2)` / `N(-d2)`,
~300 ns/op.
- P(ITM): `N(d2)` para call, `N(-d2)` para put
- P(Profit): `N(d2')` con strike efectivo `K +/- premium`
**Cuando usar**: filtrar trades con `P(Profit) > X%` en backtesting,
calcular expected value, comparar estrategias con misma prima pero
distinta P(Profit), sizing con Kelly criterion.
**CUIDADO**: la drift bajo Q es `r - q`, no la real. Para probabilidad
real-world, pasar la drift esperada como `r` (no la risk-free).
---
## Ejemplos practicos
### Backtesting de estrategia long-volatility sobre SPY
```bash
# Para cada dia historico:
# 1. Obtener IV actual (e.g. de yahoo-finance) y precio de mercado
# 2. Calcular precio teorico con IV_historica
# 3. Comparar contra precio de mercado
# Precio teorico con IV_historica
py scripts/option_pricing.py bs --S 580 --K 580 --T 0.08 --r 0.05 --sigma 0.18
# -> 12.34
# Precio teorico con IV_actual (subestimada por el mercado)
py scripts/option_pricing.py bs --S 580 --K 580 --T 0.08 --r 0.05 --sigma 0.22
# -> 15.67
# P&L esperado = (market - teorico) = 15.67 - 12.34 = +3.33 (long vol paga)
```
### Computar IV sobre toda la cadena de opciones
```bash
# Para cada strike/expiry:
py scripts/option_pricing.py iv --S 580 --K 590 --T 0.08 --r 0.05 --price 8.50
# -> 0.2145 (la IV implicita de esa opcion)
```
### Greeks para delta-hedging
```bash
py scripts/option_pricing.py greeks --S 580 --K 580 --T 0.08 --r 0.05 --sigma 0.20 --json
# Devuelve {delta: 0.512, gamma: 0.018, vega: 0.85, theta: -0.12, rho: 0.31}
# Comprar 1000 opc + short 512 acciones = delta neutral
```
### Pricing de opcion americana sobre dividendo payer
```bash
# Opcion sobre indice con yield alto (e.g. SPX con div yield ~1.5%)
py scripts/option_pricing.py bs2 --S 5800 --K 5800 --T 0.25 --r 0.05 --q 0.015 \
--sigma 0.18 --type call --style american
# -> ~123.45 (vs BS europea ~120.10, premium de early exercise = $3.35)
```
### Comparar todos los metodos aplicables
El modo `all` ejecuta todos los metodos compatibles con el `--style` elegido,
mas las utilidades (P(ITM), P(Profit), Greeks).
```bash
# Ejemplo 1: American put (Hull 21.1)
py scripts/option_pricing.py all --S 50 --K 50 --T 0.4167 --r 0.10 --sigma 0.40 \
--type put --style american
# Output (9 rows: BS, Binomial, Trinomial, MC, LSM, BS2, P(ITM), P(Profit), Greeks):
# +---------------------------+------------------+-----------------------+
# | Method | Config | Price / Value |
# +---------------------------+------------------+-----------------------+
# | Black-Scholes | closed-form O(1) | 4.076101 | (europea ref)
# | Binomial CRR | N=500 | 4.283160 |
# | Trinomial | N=500 | 4.283429 |
# | Monte Carlo | paths=100000 | 4.077892 +/- 0.0254 | (europea)
# | Longstaff-Schwartz | paths=100000 | 4.258337 |
# | BS2/BAW (closed-form) | O(1) | 4.283766 |
# | P(ITM) | N(d2) bajo Q | 0.4871 |
# | P(Profit) vs BS price | premio=4.0761 | 0.3588 |
# | Greeks (delta/gamma/vega) | BS closed-form | d=-0.3857 g=+0.0296 |
# +---------------------------+------------------+-----------------------+
# Ejemplo 2: European call (incluye Heston y Bates, NO incluye LSM/BS2)
py scripts/option_pricing.py all --S 100 --K 100 --T 0.25 --r 0.05 --sigma 0.20
# Output (9 rows: BS, Binomial, Trinomial, MC, Heston, Bates, P(ITM), P(Profit), Greeks):
# +---------------------------+----------------------------------------+-----------------------+
# | Method | Config | Price / Value |
# +---------------------------+----------------------------------------+-----------------------+
# | Black-Scholes | closed-form O(1) | 4.614997 |
# | Binomial CRR | N=500 | 4.613001 |
# | Trinomial | N=500 | 4.613999 |
# | Monte Carlo | paths=100000 | 4.620907 +/- 0.0295 |
# | Heston 1993 | v0=s2, k=2, th=s2, sv=0.3, rho=-0.5 | 4.577095 |
# | Bates 1996 | Heston + lam=1, mu_J=-0.05, sig_J=0.10 | 4.924756 |
# | P(ITM) | N(d2) bajo Q | 0.5299 |
# | P(Profit) vs BS price | premio=4.6150 | 0.3534 |
# | Greeks (delta/gamma/vega) | BS closed-form | d=+0.5695 g=+0.0393 |
# +---------------------------+----------------------------------------+-----------------------+
```
**Reglas del `all`**:
- `--style american`: incluye LSM y BS2 (los unicos metodos para americanas)
- `--style european`: incluye Heston y Bates (son european-only)
- Ambos: BS, Binomial, Trinomial, MC, P(ITM), P(Profit), Greeks
Parametros default de Heston/Bates cuando se invoca via `all` (calibrados a
equity US tipico): `v0=sigma^2, kappa=2, theta=v0, sigma_v=0.3, rho=-0.5,
lambda=1, mu_J=-0.05, sigma_J=0.10`. Para parametros custom, usar los
modos `heston` / `bates` directamente.
---
## Casos de uso NO soportados
- **Opciones path-dependent** (asianas, barrier, lookback): el skill solo
implementa MC para europeas. Extender el framework con funciones de
payoff custom.
- **Opciones exoticas multi-asset** (basket, rainbow, spread): el LSM
puede extenderse facilmente. Documentar caso por caso.
- **Dividendos discretos**: el modelo asume dividend yield continuo `q`.
Para dividendos discretos (e.g. fechas conocidas) usar q equivalente o
ajustar el modelo.
- **Stochastic volatility** (Heston, SABR): no implementado. Para
backtesting de estos modelos se necesita otra libreria (QuantLib).
---
## Performance tips para backtesting masivo
1. **Usar BS o BAW** siempre que sea posible. Son ~2000x mas rapidos que
binomial.
2. **Evitar allocs innecesarias**: para un batch de 1M opciones, las
funciones ya son O(1)/op. No se puede mejorar mucho mas en Python puro.
3. **Reusar `numpy.random.Generator`**: crear uno solo y pasar la seed a
MC/LSM. El default de la CLI ya usa `default_rng`.
4. **Vectorizar inputs**: las funciones del skill aceptan escalares. Para
vectorizar sobre un array, usar `np.vectorize(bs_price)` o mapear
manualmente. La libreria `numba` puede dar 10-50x speedup adicional
si se compila JIT.
5. **Precomputar factores comunes**: para un batch donde solo cambia S,
precomputar `T, r, q, sigma, K` y solo variar S en el loop.
---
## Validacion
El modo `validate` corre 10 casos de `assets/validation_cases.json`
(5 europeos, 4 americanos, 1 put-call parity) y reporta pass/fail:
```bash
py scripts/option_pricing.py validate
# === Black-Scholes European ===
# [OK] Hull 9th ed Example 15.6 (ATM call): got 4.7594, ref 4.7594
# [OK] ... (5/5 pass)
# === American (Binomial N=2000) ===
# [OK] Hull 9th ed Example 21.1: got 4.2841, ref 4.2841
# [OK] ... (4/4 pass)
# === Put-Call Parity (BS) ===
# [OK] C - P = 4.8770575499, S*exp(-qT) - K*exp(-rT) = 4.8770575499
# 0 failure(s)
```
Para agregar casos custom, editar `assets/validation_cases.json`.
---
## API como libreria (no solo CLI)
Las funciones se pueden importar directamente en Python:
```python
from scripts.option_pricing import bs_price, binomial_price, mc_european_price, lsm_price, bs2_american_price, bs_greeks, implied_vol
# Pricing
c = bs_price(100, 100, 0.25, 0.05, 0.0, 0.20, "call") # 4.615
p = binomial_price(100, 100, 0.25, 0.05, 0.0, 0.20, 500, "put", "european")
# Greeks (solo BS)
g = bs_greeks(100, 100, 0.25, 0.05, 0.0, 0.20, "call")
# -> {"delta": 0.569, "gamma": 0.039, "vega": 19.64, "theta": -10.47, "rho": 13.08}
# Implied vol
iv = implied_vol(4.62, 100, 100, 0.25, 0.05, 0.0, "call", "european")
# -> 0.2003
```
Todas las funciones son **flat** (sin clases), aceptan escalares y
devuelven floats. Para vectores, usar `np.vectorize` o comprehensions.
---
## Licencia
MIT
Creator's repository · gauss314/skills
License: MIT