---
title: "3.4.3 Griegas de primer y segundo orden"
description: "Delta, gamma, vega, theta, rho, vanna, volga y charm: fórmulas, diferencias finitas, QuantLib y py_vollib, unidades y explicación de un P&L real."
url: "https://pythonparatrading.com/curso-python-trading/nivel-3/griegas-de-primer-y-segundo-orden/"
lang: "es"
image: "https://pythonparatrading.com/og/curso-python-trading/nivel-3/griegas-de-primer-y-segundo-orden.png"
---

# 3.4.3 · Griegas: delta, gamma, vega, theta, rho, vanna, volga y charm

> Las griegas son las derivadas del precio de una opción respecto a lo que lo mueve. Esta lección las calcula de tres formas (fórmula, diferencias finitas y QuantLib), deja claras sus unidades, que es donde se equivoca casi todo el mundo, y las usa para explicar, término a término, lo que ganó una put de ORX el día que el índice cayó un 4,9 %.

- Curso: [Nivel 3: Derivados: futuros, spreads, forex y opciones](https://pythonparatrading.com/curso-python-trading/nivel-3/)
- Módulo: 3.4 · Teoría y valoración de opciones
- Duración: 70 min
- Requisitos: [3.4.2 · Árboles binomiales, Black-Scholes-Merton, Black-76 y Monte Carlo](https://pythonparatrading.com/curso-python-trading/nivel-3/binomial-black-scholes-black-76-y-monte-carlo/)

## Al terminar esta lección

- Definir las griegas de primer orden (delta, gamma, vega, theta, rho) y de segundo orden (vanna, volga, charm) y expresarlas en unidades operativas: por punto, por punto de volatilidad, por día natural y por punto porcentual de tipo.
- Programar sus fórmulas cerradas en Black-Scholes-Merton y comprobarlas con diferencias finitas, py_vollib y QuantLib, detectando las diferencias de convención de cada biblioteca.
- Elegir el paso de una diferencia finita y explicar el compromiso entre error de truncamiento y error de redondeo.
- Leer los perfiles de las griegas por precio, plazo y strike, y relacionar theta con gamma mediante la ecuación de Black-Scholes.
- Explicar el cambio de valor de una opción en un día con una expansión de Taylor y medir cuánto queda sin explicar.

## Qué mide cada griega

Una opción cambia de valor porque se mueven el subyacente, la volatilidad, el tiempo y el tipo de interés. Las
**griegas** son las derivadas parciales del precio respecto a cada uno: dicen cuánto cambia el precio por unidad de
cambio de cada factor, con los demás quietos. Son la herramienta con la que se cubre una cartera (lección 3.6.2), se
mide su riesgo y se explica su P&L. Las de primer orden son derivadas primeras; las de segundo orden miden cuánto
cambian las primeras.

```mermaid
flowchart TB
  V[Precio V] --> D[Delta]
  V --> VE[Vega]
  V --> TH[Theta]
  V --> RH[Rho]
  D --> G[Gamma]
  D --> VA[Vanna]
  D --> CH[Charm]
  VE --> VO[Volga]
```

La vanna está debajo de la delta y podría estar debajo de la vega: es la derivada cruzada, y las dos lecturas son la
misma. La tabla fija las **unidades** que se usan en todo el curso. Casi todos los errores con griegas son de
unidades, y cada biblioteca tiene las suyas:

| Griega | Derivada | Unidad operativa (curso) | Lectura |
|---|---|---|---|
| Delta $\Delta$ | $\partial V/\partial S$ | puntos de prima por punto de subyacente | equivalente en subyacente; ×100 = acciones o «delta en dólares» / S |
| Gamma $\Gamma$ | $\partial^2 V/\partial S^2$ | cambio de delta por punto | cuánto hay que reajustar la cobertura |
| Vega $\nu$ | $\partial V/\partial\sigma$ | puntos por **punto** de volatilidad (0,01) | ganancia si la volatilidad sube un punto |
| Theta $\Theta$ | $\partial V/\partial t$ | puntos por **día natural** | valor temporal que se consume en un día |
| Rho $\rho$ | $\partial V/\partial r$ | puntos por **punto porcentual** de tipo | ganancia si el tipo sube del 4 al 5 % |
| Vanna | $\partial^2 V/\partial S\,\partial\sigma$ | cambio de delta por punto de volatilidad | delta que cambia cuando se mueve la volatilidad |
| Volga | $\partial^2 V/\partial\sigma^2$ | cambio de vega por punto de volatilidad | convexidad en volatilidad |
| Charm | $\partial \Delta/\partial t$ | cambio de delta por día natural | deriva de la delta con el paso del tiempo |

Los precios de ORX son por punto de índice con un multiplicador de 100 USD: una delta de 0,52 en un contrato equivale
a 52 «índices» y, con el índice a 5.148, a 268.000 USD de exposición; una theta de −2,32 son 232 USD por contrato y día.

## Fórmulas cerradas en Black-Scholes-Merton

Con las mismas variables de la lección 3.4.2 ($d_1$, $d_2$, $q$ continuo) y $n(\cdot)$ la densidad normal estándar,
las de primer orden de una call son:

$$
\Delta = e^{-qT} N(d_1), \qquad \Gamma = \frac{e^{-qT} n(d_1)}{S\sigma\sqrt{T}}, \qquad
\nu = S e^{-qT} n(d_1)\sqrt{T},
$$

$$
\Theta = -\frac{S e^{-qT} n(d_1)\,\sigma}{2\sqrt{T}} - rKe^{-rT}N(d_2) + qSe^{-qT}N(d_1), \qquad
\rho = KTe^{-rT}N(d_2),
$$

y las de segundo orden, iguales para call y put salvo el charm:

$$
\text{vanna} = -e^{-qT} n(d_1)\frac{d_2}{\sigma}, \qquad
\text{volga} = \nu\,\frac{d_1 d_2}{\sigma}, \qquad
\text{charm} = q e^{-qT}N(d_1) - e^{-qT} n(d_1)\,\frac{2(r-q)T - d_2\sigma\sqrt{T}}{2T\sigma\sqrt{T}}.
$$

Gamma, vega, vanna y volga son iguales para la call y la put del mismo strike, porque la diferencia entre las dos es un
forward (paridad, lección 3.4.1), lineal en $S$ e independiente de $\sigma$. La función devuelve todas ya en las
unidades de la tabla, para una call o una put:

```python
import math
import numpy as np
import pandas as pd
from scipy.stats import norm

def griegas(S, K, T, r, q, sig, call=True):
    sq = np.sqrt(T)
    sd = sig * sq
    d1 = (np.log(S / K) + (r - q) * T) / sd + sd / 2
    d2 = d1 - sd
    eq, er, n1 = np.exp(-q * T), np.exp(-r * T), norm.pdf(d1)
    w = 1 if call else -1                 # signo de call o put
    precio = w * (S * eq * norm.cdf(w * d1)
                  - K * er * norm.cdf(w * d2))
    delta = w * eq * norm.cdf(w * d1)
    theta = (-S * eq * n1 * sig / (2 * sq)
             - w * r * K * er * norm.cdf(w * d2)
             + w * q * S * eq * norm.cdf(w * d1))
    rho = w * K * T * er * norm.cdf(w * d2)
    charm = (w * q * eq * norm.cdf(w * d1)
             - eq * n1 * (2 * (r - q) * T - d2 * sd) / (2 * T * sd))
    vega = S * eq * n1 * sq
    return {"precio": precio, "delta": delta,
            "gamma": eq * n1 / (S * sd),
            "vega": vega / 100,               # por punto de vol.
            "theta": theta / 365,             # por día natural
            "rho": rho / 100,                 # por punto de tipo
            "vanna": -eq * n1 * d2 / sig / 100,
            "volga": vega * d1 * d2 / sig / 100**2,
            "charm": charm / 365}

# la call de ORX de la lección 3.4.2
S, K, T, r, q, sig = 5148.06, 5150.0, 30 / 365, 0.04191, 0.013438, 0.217
call = griegas(S, K, T, r, q, sig)
put = griegas(S, K, T, r, q, sig, call=False)
pd.DataFrame({"call": call, "put": put}).map("{:.6g}".format)
```
```output
                call           put
precio        132.59       122.503
delta       0.524404     -0.474492
gamma     0.00124182    0.00124182
vega         5.86996       5.86996
theta       -2.31833      -1.91836
rho          2.10992       -2.1084
vanna   -8.31677e-06  -8.31677e-06
volga    7.69206e-06   7.69206e-06
charm   -0.000476373  -0.000513149
```

La call en el dinero a 30 días vale 132,59 puntos con una delta de 0,524 y la put, una de −0,474: la diferencia es
la delta del forward sintético, $e^{-qT}$ = 0,9989. Gamma, vega, vanna y volga coinciden en las dos.
Vanna y volga son casi nulas en el dinero ($d_2 \approx 0$); se ven en las alas, más abajo. La rho de la call es
positiva (un tipo más alto encarece el forward) y la de la put, negativa.

## Tres formas de calcularlas: fórmula, diferencias finitas y bibliotecas

Las fórmulas se pueden equivocar al copiarlas; las diferencias finitas, no. Una **diferencia central** aproxima la
derivada con dos precios alrededor del punto:

$$
\Delta \approx \frac{V(S+h) - V(S-h)}{2h}, \qquad \Gamma \approx \frac{V(S+h) - 2V(S) + V(S-h)}{h^2}.
$$

La celda compara las fórmulas con diferencias finitas sobre la propia función de precio, con py_vollib (paquete
`vollib`, lección 3.4.2) y con QuantLib, imprimiendo cada biblioteca en sus unidades de origen:

```python
import QuantLib as ql
from vollib.black_scholes_merton.greeks import analytical as vl

def precio(S=S, T=T, r=r, sig=sig):
    return griegas(S, K, T, r, q, sig)["precio"]

def delta_de(S=S, T=T, sig=sig):
    return griegas(S, K, T, r, q, sig)["delta"]

h, hs, hr = 1.0, 1e-4, 1e-4
dif = {
    "delta": (precio(S + h) - precio(S - h)) / (2 * h),
    "gamma": (precio(S + h) - 2 * precio() + precio(S - h)) / h**2,
    "vega": (precio(sig=sig + hs) - precio(sig=sig - hs))
            / (2 * hs) / 100,
    "theta": (precio(T=T - 1 / 365) - precio()),      # un día
    "rho": (precio(r=r + hr) - precio(r=r - hr)) / (2 * hr) / 100,
    "vanna": (delta_de(sig=sig + hs) - delta_de(sig=sig - hs))
             / (2 * hs) / 100,
    "charm": delta_de(T=T - 1 / 365) - delta_de(),     # un día
}
F = S * math.exp((r - q) * T)
bc = ql.BlackCalculator(ql.PlainVanillaPayoff(ql.Option.Call, K),
                        F, sig * math.sqrt(T), math.exp(-r * T))
origen = {
    "delta": (vl.delta("c", S, K, T, r, sig, q), bc.delta(S)),
    "gamma": (vl.gamma("c", S, K, T, r, sig, q), bc.gamma(S)),
    "vega": (vl.vega("c", S, K, T, r, sig, q), bc.vega(T)),
    "theta": (vl.theta("c", S, K, T, r, sig, q), bc.theta(S, T)),
    "rho": (vl.rho("c", S, K, T, r, sig, q), bc.rho(T)),
    "vanna": (np.nan, bc.vanna(S, T)),
    "charm": (np.nan, np.nan),
}
pd.DataFrame({"fórmula": {k: call[k] for k in dif},
              "dif. finitas": dif,
              "vollib": {k: v[0] for k, v in origen.items()},
              "QuantLib (origen)": {k: v[1]
                                    for k, v in origen.items()}}
             ).map("{:.6g}".format)
```
```output
            fórmula  dif. finitas      vollib QuantLib (origen)
delta      0.524404      0.524404    0.524404          0.524404
gamma    0.00124182    0.00124182  0.00124182        0.00124182
vega        5.86996       5.86996     5.86996           586.996
theta      -2.31833      -2.33649    -2.31833          -846.192
rho         2.10992       2.10992     2.10992           210.992
vanna  -8.31677e-06   -8.3169e-06         nan      -0.000831677
charm  -0.000476373  -0.000481304         nan               nan
```

Fórmula y diferencias finitas coinciden en todas las griegas instantáneas. Theta y charm por diferencia de **un día**
son algo mayores en valor absoluto (−2,336 frente a −2,318 por día): la theta de la fórmula es una tasa instantánea, y
el valor temporal se consume cada vez más deprisa al acercarse el vencimiento. py_vollib da ya las unidades
operativas: vega y rho divididas por 100 y theta por 365. QuantLib da la vega (587,0) y la rho (210,99) por unidad,
es decir, por un salto de 100 puntos de volatilidad o de tipo, y la theta por año (−846,19); para la theta diaria
tiene `thetaPerDay`. Ninguna está mal: miden lo mismo en otras unidades, y un sistema que mezcle dos bibliotecas sin
convertir las unidades puede cubrir cien veces de más o de menos.

Con la volga hay una sorpresa. QuantLib 1.44 tiene `BlackCalculator.volga(T)`, pero su valor no coincide con la
derivada segunda respecto a σ salvo con $T = 1$:

```python
filas = []
for Tx in [0.25, 1.0, 4.0]:
    Fx = S * math.exp((r - q) * Tx)
    v = lambda s: ql.BlackCalculator(
        ql.PlainVanillaPayoff(ql.Option.Call, 5000.0), Fx,
        s * math.sqrt(Tx), math.exp(-r * Tx)).value()
    bcx = ql.BlackCalculator(ql.PlainVanillaPayoff(ql.Option.Call,
                                                   5000.0),
                             Fx, sig * math.sqrt(Tx),
                             math.exp(-r * Tx))
    fd = (v(sig + 1e-3) - 2 * v(sig) + v(sig - 1e-3)) / 1e-6
    filas.append({"T": Tx, "QuantLib volga": bcx.volga(Tx),
                  "dif. finitas": fd,
                  "cociente": bcx.volga(Tx) / fd,
                  "1/sqrt(T)": 1 / math.sqrt(Tx)})
pd.DataFrame(filas).round(4)
```
```output
      T  QuantLib volga  dif. finitas  cociente  1/sqrt(T)
0  0.25        953.2139      476.6165       2.0        2.0
1  1.00        512.1042      512.1166       1.0        1.0
2  4.00        475.6863      951.4064       0.5        0.5
```

El cociente es exactamente $1/\sqrt{T}$: la «volga» de `BlackCalculator` es la derivada de la vega respecto a la
desviación típica total $\sigma\sqrt{T}$, no respecto a $\sigma$. Para usarla como volga hay que multiplicarla por
$\sqrt{T}$. No es un error del método sino de convención (o de documentación), y solo se ve comprobándolo. Esa es la
regla de la lección: **ninguna griega de una biblioteca se usa sin contrastarla una vez con diferencias finitas**.

### El paso de la diferencia finita

Un paso $h$ grande da un error de truncamiento (la diferencia central yerra en $h^2$ por la derivada siguiente); uno
pequeño da un error de **redondeo**: con precisión doble ($\varepsilon \approx 2{,}2\cdot 10^{-16}$), restar dos precios
casi iguales de 132 puntos y dividir por $h^2$ amplifica ese épsilon. Para gamma el error total es del orden de
$c_1 h^2 + c_2\,\varepsilon V/h^2$, mínimo con $h \propto \varepsilon^{1/4}$, del orden de una diezmilésima del
subyacente (unos 0,6 puntos con ORX a 5.148):

```python
pasos = 10.0 ** np.arange(-4, 2.75, 0.25)
gamma_fd = np.array([(precio(S + x) - 2 * precio() + precio(S - x))
                     / x**2 for x in pasos])
err_rel = np.abs(gamma_fd / call["gamma"] - 1)
mejor = pasos[err_rel.argmin()]
print(f"Paso con menor error: {mejor:.2f} puntos "
      f"(error relativo {err_rel.min():.1e})")
for x in [1e-4, 1e-3, 1e-2, 1.0, 100.0]:
    i = np.argmin(abs(pasos - x))
    print(f"h = {x:g}: error relativo {err_rel[i]:.1e}")
```
```output
Paso con menor error: 0.06 puntos (error relativo 1.1e-08)
h = 0.0001: error relativo 1.1e-02
h = 0.001: error relativo 2.9e-04
h = 0.01: error relativo 3.8e-06
h = 1: error relativo 7.9e-07
h = 100: error relativo 7.9e-03
```

*Fig. — Error relativo de la gamma calculada con una diferencia central según el paso, call de ORX en el dinero a 30 días.* Curva en V en escala log-log: con pasos de 0,0001 puntos el error es del 1,1 % (punto destacado de la izquierda) por redondeo; baja a entre una millonésima y una cienmillonésima entre 0,01 y unos pocos puntos y vuelve a subir por truncamiento hasta el 0,8 % con 100 puntos (punto destacado de la derecha).

Con pasos de una diezmilésima de punto la gamma numérica es basura (un error del 1,1 %); entre 0,01 y unos pocos puntos, el
error es de millonésimas o menos (el mínimo medido, en 0,06 puntos, es en parte suerte del redondeo); con 100 puntos vuelve a crecer por truncamiento. La figura dibuja la V completa. Para la
vega y la rho el compromiso es el mismo con otra escala: $10^{-4}$ en volatilidad o tipo está cerca del óptimo.

### Diferencias finitas con QuantLib: mover las cotizaciones

Para lo que una biblioteca no da (vanna, volga, charm en QuantLib con un motor cualquiera) se mueve la entrada y se
revalora. En QuantLib las entradas son **cotizaciones observables** (`SimpleQuote`): al cambiar su valor, todo lo que
depende de ellas se recalcula solo. Para el charm, se mueve la fecha de valoración un día con curvas que se desplazan
con ella (las que se crean con `settlementDays = 0`):

```python
hoy = ql.Date(18, 6, 2025)
ql.Settings.instance().evaluationDate = hoy
dc, cal = ql.Actual365Fixed(), ql.NullCalendar()
q_s, q_v = ql.SimpleQuote(S), ql.SimpleQuote(sig)

def plana(x):
    return ql.YieldTermStructureHandle(ql.FlatForward(
        0, cal, ql.QuoteHandle(ql.SimpleQuote(x)), dc))

proceso = ql.BlackScholesMertonProcess(
    ql.QuoteHandle(q_s), plana(q), plana(r),
    ql.BlackVolTermStructureHandle(
        ql.BlackConstantVol(0, cal, ql.QuoteHandle(q_v), dc)))
opcion = ql.VanillaOption(ql.PlainVanillaPayoff(ql.Option.Call, K),
                          ql.EuropeanExercise(hoy + 30))
opcion.setPricingEngine(ql.AnalyticEuropeanEngine(proceso))

def con(quote, valor, f):
    viejo = quote.value()
    quote.setValue(valor)
    x = f()
    quote.setValue(viejo)
    return x

vanna = (con(q_v, sig + hs, opcion.delta)
         - con(q_v, sig - hs, opcion.delta)) / (2 * hs) / 100
volga = (con(q_v, sig + hs, opcion.vega)
         - con(q_v, sig - hs, opcion.vega)) / (2 * hs) / 100**2
d_hoy = opcion.delta()
ql.Settings.instance().evaluationDate = hoy + 1
charm = opcion.delta() - d_hoy
ql.Settings.instance().evaluationDate = hoy
print(f"vanna {vanna:.3e} (fórmula {call['vanna']:.3e})")
print(f"volga {volga:.3e} (fórmula {call['volga']:.3e})")
print(f"charm a un día {charm:.3e} (fórmula {call['charm']:.3e})")
```
```output
vanna -8.317e-06 (fórmula -8.317e-06)
volga 7.692e-06 (fórmula 7.692e-06)
charm a un día -4.813e-04 (fórmula -4.764e-04)
```

Las tres coinciden con las fórmulas (el charm, con la diferencia de un día frente a la tasa instantánea ya vista en
theta). Mover una cotización y revalorar es también la forma de calcular griegas en modelos sin fórmula: un árbol para
una americana (lección 3.4.2) o Heston (lección 3.4.7).

## Perfiles: dónde se concentra cada griega

La figura de la cabecera dibuja gamma en función del índice para tres plazos, con la volatilidad de la call de ORX:
gamma es una campana centrada cerca del strike que se estrecha y crece al acercarse el vencimiento. En el dinero crece
como $1/\sqrt{T}$: a 7 días es el doble que a 30 y casi cuatro veces la de 90. Theta sigue a gamma, porque la ecuación
de Black-Scholes las ata. Para cualquier opción europea en ese modelo:

$$
\Theta + \tfrac{1}{2}\sigma^2 S^2\,\Gamma + (r - q) S\,\Delta - rV = 0.
$$

Quien está largo de gamma (gana con los movimientos grandes en cualquier dirección) paga theta cada día; quien la
vende, la cobra. Es el intercambio que explotan el gamma scalping y la venta de prima (lecciones 3.6.1 y 3.6.2). La
celda calcula las griegas en el dinero para los tres plazos y comprueba la ecuación con las unidades anuales:

```python
filas = []
for dias in [7, 30, 90]:
    g = griegas(S, K, dias / 365, r, q, sig)
    pde = (365 * g["theta"] + 0.5 * sig**2 * S**2 * g["gamma"]
           + (r - q) * S * g["delta"] - r * g["precio"])
    filas.append({"días": dias, "precio": g["precio"],
                  "gamma": g["gamma"], "theta": g["theta"],
                  "vega": g["vega"],
                  "theta/precio (%)": 100 * g["theta"] / g["precio"],
                  "ecuación BS": pde})
pd.DataFrame(filas).set_index("días").map("{:.4g}".format)
```
```output
     precio     gamma   theta   vega theta/precio (%) ecuación BS
días
7     62.13  0.002578  -4.603  2.843           -7.409  -2.078e-13
30    132.6  0.001242  -2.318   5.87           -1.749  -2.567e-13
90    237.1  0.000712  -1.409   10.1           -0.594  -1.492e-13
```

A 7 días la call vale 62,13 puntos y pierde 4,60 al día, un 7,4 % de su valor; a 90 días pierde 1,41 al día, un 0,59 %. La
vega se comporta al revés que la gamma: crece con $\sqrt{T}$, así que las opciones largas son las que más exponen a la
volatilidad y las cortas las que más exponen al movimiento. La ecuación de Black-Scholes da cero en los tres plazos
salvo el redondeo de la coma flotante.

## Las griegas de una cadena: delta, probabilidad y alas

En una cadena real cada strike tiene su volatilidad implícita (la sonrisa, lección 3.4.5), y las griegas se calculan
con la de su strike. La celda lo hace con el vencimiento de 30 días de ORX del 18 de junio de 2025 y la columna
`iv_modelo`:

```python
cad = pd.read_parquet("opciones3_cadena.parquet")
c30 = cad[(cad["fecha"] == "2025-06-18")
          & (cad["vencimiento"] == "2025-07-18")
          & (cad["tipo"] == "C")].copy()
g = griegas(S, c30["strike"], T, r, q, c30["iv_modelo"])
for k in ["delta", "gamma", "vega", "vanna", "volga"]:
    c30[k] = g[k]
sd = c30["iv_modelo"] * math.sqrt(T)
d2 = (np.log(S / c30["strike"]) + (r - q) * T) / sd - sd / 2
c30["N(d2)"] = norm.cdf(d2)
c30["delta_usd"] = 100 * S * c30["delta"]   # por contrato
sel = c30["strike"].isin([4600.0, 4900.0, 5150.0, 5400.0, 5700.0])
c30.loc[sel, ["strike", "iv_modelo", "delta", "N(d2)", "delta_usd",
              "gamma", "vega", "vanna", "volga"]].round(5)
```
```output
        strike  iv_modelo    delta    N(d2)     delta_usd    gamma     vega    vanna    volga
519219  4600.0     0.3300  0.89551  0.87844  461011.41198  0.00037  2.65304 -0.00636  0.11841
519225  4900.0     0.2705  0.75899  0.73507  390734.43659  0.00078  4.58487 -0.00721  0.07515
519230  5150.0     0.2170  0.52440  0.50018  269966.39702  0.00124  5.86996 -0.00001  0.00001
519235  5400.0     0.1722  0.18500  0.17231   95237.01786  0.00105  3.93792  0.01464  0.19359
519240  5700.0     0.1615  0.01673  0.01492    8614.73892  0.00017  0.61380  0.00559  0.17552
```

Dos lecturas de la tabla:

- **Delta no es la probabilidad de ejercicio.** La probabilidad neutral al riesgo de acabar dentro es $N(d_2)$, no
  $N(d_1)$: en la call de 5.400 la delta es 0,185 y $N(d_2)$, 0,172. La diferencia crece con la volatilidad y el plazo. Y
  las dos son probabilidades neutrales al riesgo, no previsiones (lección 3.4.2).
- **Vanna y volga viven en las alas.** En el dinero son casi nulas; en la call de 4.600 (muy dentro) la vanna es
  −0,0064 y en la de 5.400 (fuera), +0,0146: subir la volatilidad baja la delta de las calls dentro del dinero y sube la de las
  de fuera. La volga es positiva en las alas: las opciones lejanas ganan con la volatilidad de forma convexa, y por
  eso el mercado las paga más caras (parte de la explicación de la sonrisa, lección 3.4.5).

*Fig. — Vanna y volga de las calls de ORX por strike, vencimiento de 30 días, 18 de junio de 2025, con la volatilidad de cada strike.* Dos paneles con los strikes de 4.300 a 6.000. Arriba, la vanna (por mil): negativa por debajo del dinero, hasta unos −7,5 en 4.800, cero cerca del strike en el dinero (5.150, línea destacada) y positiva por encima, con un máximo de unos 15 en 5.450. Abajo, la volga: casi cero en el dinero y positiva en las dos alas, con un máximo de unas 0,27 en 5.500.

## Explicar un P&L con las griegas

La utilidad diaria de las griegas es descomponer lo que ha ganado o perdido una posición. Con una expansión de Taylor
del precio hasta el segundo orden:

$$
\Delta V \approx \Delta\,\delta S + \tfrac{1}{2}\Gamma\,\delta S^2 + \nu\,\delta\sigma + \Theta\,\delta t + \rho\,\delta r
+ \text{vanna}\,\delta S\,\delta\sigma + \tfrac{1}{2}\text{volga}\,\delta\sigma^2 + \text{charm}\,\delta t\,\delta S.
$$

El 3 de abril de 2025 ORX cayó un 4,9 % en un día (uno de los saltos plantados en los datos, como el del S&P 500 de
ese día). Se toma la put en el dinero del vencimiento de mayo, valorada al cierre del 2 de abril y del 3 con
Black-Scholes-Merton, el índice, la curva, el dividendo y la `iv_modelo` de su strike de cada día:

```python
ind = pd.read_csv("opciones3_indice.csv", parse_dates=["fecha"],
                  index_col="fecha")
plazos = np.array([1 / 12, 0.25, 0.5, 1.0, 2.0])
cols = ["tipo_1m", "tipo_3m", "tipo_6m", "tipo_1a", "tipo_2a"]

def estado(fecha, venc, strike, tipo):
    f, v = pd.Timestamp(fecha), pd.Timestamp(venc)
    Tf = (v - f).days / 365
    fila = cad[(cad["fecha"] == f) & (cad["vencimiento"] == v)
               & (cad["strike"] == strike)
               & (cad["tipo"] == tipo)].iloc[0]
    return {"S": float(ind.loc[f, "cierre"]), "T": Tf,
            "r": float(np.interp(Tf, plazos,
                                 ind.loc[f, cols].to_numpy(float)
                                 / 100)),
            "q": float(ind.loc[f, "rentabilidad_dividendo"]) / 100,
            "sig": float(fila["iv_modelo"]),
            "medio": (fila["bid"] + fila["ask"]) / 2}

def atribucion(f0, f1, venc, strike, tipo):
    a, b = estado(f0, venc, strike, tipo), estado(f1, venc, strike,
                                                  tipo)
    es_call = tipo == "C"
    g = griegas(a["S"], strike, a["T"], a["r"], a["q"], a["sig"],
                es_call)
    v1 = griegas(b["S"], strike, b["T"], b["r"], b["q"], b["sig"],
                 es_call)["precio"]
    dS, dsig = b["S"] - a["S"], 100 * (b["sig"] - a["sig"])
    dt = (pd.Timestamp(f1) - pd.Timestamp(f0)).days
    dr = 100 * (b["r"] - a["r"])
    partes = pd.Series({
        "delta": g["delta"] * dS, "gamma": 0.5 * g["gamma"] * dS**2,
        "vega": g["vega"] * dsig, "theta": g["theta"] * dt,
        "rho": g["rho"] * dr, "vanna": g["vanna"] * dS * dsig,
        "volga": 0.5 * g["volga"] * dsig**2,
        "charm": g["charm"] * dt * dS})
    partes["residuo"] = (v1 - g["precio"]) - partes.sum()
    partes["total (modelo)"] = v1 - g["precio"]
    partes["total (medios)"] = b["medio"] - a["medio"]
    print(f"S {a['S']} a {b['S']} ({dS / a['S']:+.2%}); vol. "
          f"{a['sig']} a {b['sig']}; {dt} día(s)")
    return partes.round(2)

atribucion("2025-04-02", "2025-04-03", "2025-05-16", 5200.0, "P")
```
```output
S 5211.08 a 4956.94 (-4.88%); vol. 0.2252 a 0.2314; 1 día(s)
delta             115.59
gamma              31.37
vega                4.44
theta              -1.62
rho                -0.01
vanna               0.09
volga               0.00
charm               0.07
residuo            -0.06
total (modelo)    149.87
total (medios)    150.05
dtype: float64
```

La put ganó 149,87 puntos en el modelo (150,05 con los precios medios de pantalla: 15.005 USD por contrato). La delta
explica 115,59; la gamma, 31,37 más, porque con 254 puntos de caída la aproximación lineal se queda corta; la vega,
4,44 (la volatilidad de ese strike subió 0,62 puntos); la theta resta 1,62. Rho, vanna, volga y charm no llegan a
0,1. Queda sin explicar −0,06: los términos de tercer orden. La figura lo muestra en barras:

*Fig. — Atribución del P&L de una put de ORX en el dinero el 3 de abril de 2025, día en que el índice cayó un 4,9 %.* Barras horizontales en puntos de índice: delta +115,59, gamma +31,37 (destacada), vega +4,44, theta −1,62, el resto de griegas (rho, vanna, volga y charm) +0,15 y un residuo de −0,06; el total del modelo es +149,87.

Ese día el reparto es el de libro: una posición corta en esa put con cobertura delta habría perdido la gamma (31
puntos) más la vega (4,4) y solo habría cobrado 1,6 de theta. Es el riesgo de la venta de opciones en una frase, y la
razón por la que la lección 3.6.1 presenta la venta de prima con su peor episodio y no con su Sharpe.

## Errores típicos

- **Unidades de biblioteca.** Vega y rho de QuantLib por unidad, theta por año; py_vollib por punto y por día; la volga
  de `BlackCalculator` respecto a $\sigma\sqrt{T}$. Se convierten en un único sitio del código y se prueban.
- **Theta por día hábil o natural.** Con $T$ en días naturales / 365, el fin de semana consume tres días de theta. Si
  el sistema usa días hábiles para $T$, la volatilidad tiene que estar en la misma base.
- **Diferencias finitas con pasos ridículos.** $h = 10^{-8}$ no es más preciso: es ruido. Para gamma, del orden de una
  diezmilésima del subyacente; para la vega, $10^{-4}$ en volatilidad.
- **Griegas con la volatilidad equivocada.** Una griega se calcula con la volatilidad de su strike. Y cuando el índice
  se mueve, la volatilidad de cada strike también se mueve (en ORX subió al caer el índice): la delta «de la fórmula»
  supone el strike pegado a su volatilidad (sticky strike) y no incluye ese efecto. Se discute con la superficie en la
  lección 3.4.5.
- **Griegas en dólares sin el multiplicador.** Una gamma de 0,00124 por punto parece nada, pero en un contrato de 100 USD sobre un
  índice a 5.148 la delta en dólares cambia unos 640 USD por punto (100 × 5.148 × 0,00124) y unos 33.000 USD con un
  movimiento del 1 %: la escala del contrato decide si una griega es pequeña.

## Ejercicios

1. Repite la atribución de la call y la put en el dinero del vencimiento de mayo entre el 8 y el 9 de abril de 2025,
   cuando ORX subió un 9,5 % y la volatilidad de esos strikes subió casi 9 puntos. ¿Cuánto queda sin explicar y por
   qué?

**Solución.**

```python
pd.DataFrame({
    "call": atribucion("2025-04-08", "2025-04-09", "2025-05-16",
                       4800.0, "C"),
    "put": atribucion("2025-04-08", "2025-04-09", "2025-05-16",
                      4800.0, "P")})
```
```output
S 4820.64 a 5279.9 (+9.53%); vol. 0.3532 a 0.4403; 1 día(s)
S 4820.64 a 5279.9 (+9.53%); vol. 0.3532 a 0.4403; 1 día(s)
                  call     put
delta           251.29 -207.29
gamma            75.92   75.92
vega             53.58   53.58
theta            -3.04   -2.67
rho               0.01   -0.01
vanna            -0.29   -0.29
volga             0.01    0.01
charm            -0.10   -0.12
residuo         -19.26  -19.92
total (modelo)  358.11 -100.80
total (medios)  358.80 -101.15
```

Con un salto del 9,5 % y casi 9 puntos de volatilidad, el residuo es de unos −19 puntos en las dos opciones, un 5 %
del cambio de la call. Los términos de tercer orden ya no son despreciables: la derivada de gamma respecto al
subyacente (speed) multiplicada por $\delta S^3/6$, y las derivadas cruzadas de gamma y de vega con la volatilidad. El
reparto sigue siendo útil (delta, gamma y vega explican casi todo), pero un sistema de riesgo que solo use griegas en
días así infravalora las pérdidas: para los escenarios extremos se revalora la posición entera (lección 3.5.4).

2. Comprueba la ecuación de Black-Scholes en todas las calls y puts de 30 días de la cadena de la lección, cada una con
   su `iv_modelo`. ¿Se cumple con volatilidades distintas en cada strike?

**Solución.**

```python
c30_all = cad[(cad["fecha"] == "2025-06-18")
              & (cad["vencimiento"] == "2025-07-18")]
max_err = 0.0
for tipo in ["C", "P"]:
    x = c30_all[c30_all["tipo"] == tipo]
    sx = x["iv_modelo"]
    gx = griegas(S, x["strike"], T, r, q, sx, call=tipo == "C")
    pde = (365 * gx["theta"] + 0.5 * sx**2 * S**2 * gx["gamma"]
           + (r - q) * S * gx["delta"] - r * gx["precio"])
    max_err = max(max_err, float(np.abs(pde).max()))
print(f"{len(c30_all)} opciones; residuo máximo {max_err:.1e}")
```
```output
90 opciones; residuo máximo 3.1e-13
```

Se cumple en todas, con residuos de coma flotante, porque cada opción se valora con una volatilidad constante: la
suya. Eso no significa que la superficie sea coherente con un único proceso del subyacente (con volatilidades
distintas por strike, no lo es: es justo lo que modelan la volatilidad local y Heston, lección 3.4.7), solo que cada
precio, aislado, es un precio de Black-Scholes.

3. Tienes una cartera de opciones de ORX con delta 0, gamma de −0,05 por punto, vega de −800 por punto de volatilidad
   y theta de +90 por día (todo en puntos de índice, sin multiplicador). Si mañana el índice cae 100 puntos y la
   volatilidad sube 3 puntos, ¿cuánto pierdes aproximadamente? ¿Qué griega domina?

**Solución.**

Con la expansión de Taylor: gamma, $\tfrac{1}{2} \cdot (-0{,}05) \cdot 100^2 = -250$ puntos; vega, $-800 \cdot 3 =
-2.400$; theta, $+90$. En total, unos −2.560 puntos de índice, 256.000 USD con el multiplicador de 100. Domina la vega:
la cartera está corta de volatilidad, y un día de caída con subida de volatilidad es su peor escenario. Habría que
añadir vanna y volga si la cartera tiene opciones lejanas, y revalorar la posición completa para movimientos mayores.

## Autoevaluación

1. py_vollib devuelve para una call una vega de 5,87 y QuantLib, para la misma opción, de 587. ¿Qué pasa?

   - A. Una de las dos bibliotecas está mal
   - B. Son la misma vega en unidades distintas: py_vollib la da por punto de volatilidad (0,01) y QuantLib por unidad de volatilidad (1,00)
   - C. QuantLib la da por contrato con el multiplicador de 100
   - D. py_vollib usa días hábiles

   *Respuesta B: Son la misma vega en unidades distintas: py_vollib la da por punto de volatilidad (0,01) y QuantLib por unidad de volatilidad (1,00).* Una subida de la volatilidad del 21,7 % al 22,7 % sube la call 5,87 puntos. QuantLib devuelve la derivada respecto a σ en tanto por uno (un salto de 100 puntos de volatilidad), así que hay que dividir por 100. Con theta pasa lo mismo: QuantLib la da por año (`theta`) o por día (`thetaPerDay`); py_vollib, por día.

2. Al calcular gamma con una diferencia central de pasos cada vez más pequeños, el error primero baja y después vuelve a subir. ¿Por qué?

   - A. Porque gamma no existe en el dinero
   - B. Porque el error de truncamiento cae con el paso al cuadrado, pero el de redondeo crece como el épsilon de la máquina por el precio dividido por el paso al cuadrado
   - C. Porque NumPy pierde precisión con los logaritmos
   - D. Porque la fórmula analítica está mal

   *Respuesta B: Porque el error de truncamiento cae con el paso al cuadrado, pero el de redondeo crece como el épsilon de la máquina por el precio dividido por el paso al cuadrado.* Con un precio de 132 puntos y precisión doble, restar dos precios casi iguales y dividir por h² amplifica el redondeo. En la call de ORX el error es de millonésimas o menos con pasos de entre 0,01 y unos pocos puntos de índice; con pasos de 0,0001 llega al 1 %.

3. Una call en el dinero a 30 días tiene theta de −2,32 puntos por día. ¿Cuánto pierde, con todo lo demás igual, entre el viernes y el lunes?

   - A. 2,32: solo cuenta un día hábil
   - B. Unos 7: el plazo se mide en días naturales y pasan tres
   - C. Nada: en fin de semana no hay mercado
   - D. 4,64

   *Respuesta B: Unos 7: el plazo se mide en días naturales y pasan tres.* Con T en días naturales / 365, el valor temporal se consume también el fin de semana. Una theta por día natural se multiplica por los días naturales que pasan. Quien mida theta por día hábil la tiene que definir así en todo el sistema; mezclar convenciones descuadra el P&L de los lunes.

4. ¿Qué mide la vanna?

   - A. Cuánto cambia la vega con el paso del tiempo
   - B. Cuánto cambia la delta cuando sube la volatilidad (o, lo que es lo mismo, cuánto cambia la vega cuando sube el subyacente)
   - C. La curvatura del precio respecto a la volatilidad
   - D. La sensibilidad al dividendo

   *Respuesta B: Cuánto cambia la delta cuando sube la volatilidad (o, lo que es lo mismo, cuánto cambia la vega cuando sube el subyacente).* Es la derivada cruzada del precio respecto al subyacente y a la volatilidad. Es casi nula en el dinero y grande en las alas, con signo contrario a cada lado: por eso una cartera delta neutral en strikes lejanos deja de serlo cuando la volatilidad se mueve. La curvatura respecto a la volatilidad es la volga; el cambio de la delta con el tiempo, el charm.

5. El 3 de abril de 2025 ORX cae un 4,9 % y una put en el dinero de mayo gana 149,87 puntos. La delta explica 115,59. ¿De dónde sale casi todo el resto?

   - A. De la vega
   - B. De la gamma: con una caída de 254 puntos, el término de segundo orden en el índice aporta 31,37
   - C. De la rho
   - D. Del redondeo

   *Respuesta B: De la gamma: con una caída de 254 puntos, el término de segundo orden en el índice aporta 31,37.* Con movimientos grandes la aproximación lineal se queda corta y el término de segundo orden en el precio pesa: 31,37 puntos, frente a 4,44 de la vega (la volatilidad de ese strike subió 0,62 puntos) y −1,62 de theta. Lo que queda sin explicar es −0,06.

## Ideas clave

- Las griegas son derivadas del precio: delta y gamma respecto al subyacente, vega y volga respecto a la volatilidad, theta y charm respecto al tiempo, rho respecto al tipo y vanna, cruzada entre subyacente y volatilidad.
- Las unidades deciden: vega por punto de volatilidad, theta por día natural, rho por punto porcentual de tipo; QuantLib da vega y rho por unidad y theta por año, py_vollib ya las divide.
- Comprobar con diferencias finitas es obligatorio: así se ve que `BlackCalculator.volga` de QuantLib 1.44 está escrita respecto a la desviación típica total (σ por la raíz de T) y no respecto a σ.
- El paso de una diferencia finita no puede ser arbitrariamente pequeño: el redondeo crece al reducirlo. Para gamma sobre un índice de 5.000 puntos, entre centésimas y unos pocos puntos.
- Gamma se concentra en el dinero y crece al acercarse el vencimiento; theta es su contrapartida por la ecuación de Black-Scholes.
- Una expansión de Taylor con delta, gamma, vega y theta explica el P&L diario de una opción casi entero; en días de movimientos extremos, los términos de tercer orden dejan residuos visibles.

## Recursos

### Research

- [Estimadores de Volatilidad](https://pythonparatrading.com/estimadores-de-volatilidad-para-trading/) · Research-0002 · 4 min

### Documentación

- [QuantLib: documentación de la biblioteca (VanillaOption, BlackCalculator)](https://www.quantlib.org/docs.shtml) · quantlib.org
- [py_vollib (vollib): documentación de las griegas analíticas y numéricas](https://vollib.org/) · vollib.org

### Libros

- [John C. Hull, Options, Futures, and Other Derivatives (Pearson, 11.ª ed., 2021)](https://www.pearson.com/en-us/subject-catalog/p/options-futures-and-other-derivatives/P200000005938) · pearson.com
- [Black, F. y Scholes, M. (1973): The Pricing of Options and Corporate Liabilities. Journal of Political Economy 81(3), 637-654](https://doi.org/10.1086/260062) · doi.org

### Datos

- [Datos del nivel 3: cadena diaria de opciones sobre ORX (Parquet)](https://pythonparatrading.com/curso/datos/nivel-3/opciones3_cadena.parquet) · Descarga · opciones3_cadena.parquet

Lección anterior: [3.4.2 · Árboles binomiales, Black-Scholes-Merton, Black-76 y Monte Carlo](https://pythonparatrading.com/curso-python-trading/nivel-3/binomial-black-scholes-black-76-y-monte-carlo/)

Lección siguiente: [3.4.4 · Volatilidad implícita: Newton-Raphson, Brent, py_vollib y QuantLib](https://pythonparatrading.com/curso-python-trading/nivel-3/volatilidad-implicita-newton-brent-py-vollib-y-quantlib/)
