σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft AcademyRutas
Ctrl K
AO
+1,2 k estudiantes
Iniciar sesiónUnirse ↗
Rutas
AO
+1,2 k estudiantes
Iniciar sesión
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Ruta de Python›Módulo 3 · Probabilidad y simulación Monte Carlo›Tema 3.8·~40 minIntermedio

Drawdowns

Posición en la rutaMódulo 3 de 11 · Tema 8 de 12
3.8 Drawdowns
—Puntuación del lab— / 100XP total—Racha—

La pérdida que realmente se siente

La volatilidad trata igual la subida y la bajada, pero el inversor vive con otro número: cuánto está su cuenta por debajo del mejor valor que ha tenido. Eso es el drawdown. Si una cartera subió a 110 y ahora vale 98, está un 10,9 % por debajo de su máximo, diga lo que diga la volatilidad diaria. El drawdown máximo es el agujero más profundo del historial y el tiempo bajo el agua es lo que tardó en salir. Los clientes se van y los gestores de riesgo recortan límites ante los drawdowns, no ante las desviaciones típicas.

import pandas as pd

prices = pd.Series(
    [100, 105, 103, 98, 104, 110, 108, 107, 111, 95], dtype=float,
    index=pd.bdate_range("2026-03-02", periods=10),
)

peak = prices.cummax()                 # the highest price so far, day by day
drawdown = prices / peak - 1           # 0 on a new high, negative below it

print(peak.tolist())                   # [100.0, 105.0, 105.0, 105.0, 105.0, 110.0, 110.0, 110.0, 111.0, 111.0]
print(drawdown.round(4).tolist())      # [0.0, 0.0, -0.019, -0.0667, -0.0095, 0.0, -0.0182, -0.0273, 0.0, -0.1441]

El agujero más profundo

cummax() da el máximo acumulado en una llamada. Dividir el precio entre él y restar 1 da el drawdown de cada día, siempre cero o negativo. El drawdown máximo es simplemente el mínimo de esa serie, e idxmin() dice cuándo ocurrió. Los drawdowns son asimétricos de una forma que importa: una pérdida del 20 % necesita una ganancia del 25 % para recuperarse, 1 / (1 - 0,20) - 1, y una del 50 % necesita el 100 %. Por eso los gestores de riesgo luchan por mantener los drawdowns poco profundos.

print(round(drawdown.min(), 4), drawdown.idxmin().date())   # -0.1441 2026-03-13   111 down to 95

# The climb back is steeper than the fall
for loss in (0.10, 0.20, 0.50):
    print(loss, round(1 / (1 - loss) - 1, 3))
# 0.1 0.111
# 0.2 0.25
# 0.5 1.0

El tiempo bajo el agua

La profundidad es la mitad de la historia; la duración es la otra mitad. Una estrategia puede perder solo un 8 % y aun así pasar tres años por debajo de su antiguo máximo, lo que pone a prueba la paciencia de cualquier inversor. Un día está bajo el agua mientras su drawdown es negativo, y un nuevo máximo termina el tramo. Para hallar el tramo más largo con pandas, marca los días bajo el agua con una comparación, etiqueta cada racha de valores iguales con (flag != flag.shift()).cumsum() y cuenta dentro de cada racha. Un simple bucle que cuenta y reinicia funciona igual de bien y se lee fácilmente.

underwater = drawdown < 0                                     # True while below the running peak
run_id = (underwater != underwater.shift()).cumsum()           # a new id each time the flag changes
streak = underwater.astype(int).groupby(run_id).cumsum()       # 1, 2, 3, ... inside each underwater run

print(streak.tolist())                    # [0, 0, 1, 2, 3, 0, 1, 2, 0, 1]
print(int(streak.max()))                  # 3   the longest wait for a new high, in days
# Return divided by the depth of the worst hole: the Calmar ratio
annual_return = 0.12
print(round(annual_return / abs(drawdown.min()), 2))     # 0.83
Un drawdown pasado no es el peorEl drawdown máximo de un backtest es el peor ocurrido en esa muestra, no el peor posible: un historial más largo casi siempre contendrá un agujero más profundo. Trátalo como una cota inferior, compáralo con el mayor drawdown del mercado en el mismo periodo y deja un margen al dimensionar las posiciones.
  • peak = prices.cummax() y drawdown = prices / peak - 1: cero con un nuevo máximo, negativo por debajo.
  • El drawdown máximo es drawdown.min(); una pérdida de x necesita una ganancia de 1 / (1 - x) - 1 para recuperarse.
  • El tiempo bajo el agua es la racha más larga de días con drawdown negativo; el peor drawdown de un backtest es una cota inferior, no una garantía.

A continuación: los generadores de números aleatorios y las semillas, la base de toda simulación.

Lab: qué se califica

  • Seguir el máximo alcanzado con running_peak25 pts
  • Medir la distancia al máximo con drawdown_series25 pts
  • Encontrar la peor caída con max_drawdown25 pts
  • Contar la espera más larga por un nuevo máximo con longest_underwater25 pts
Explorador · lab-61-1
▾ lab-61-1
…
bash · en el navegador
learner@quantcraft:~/lab-61-1$
Python aún no cargadoPythonLn 1, Col 1Spaces: 4UTF-8

¿Restablecer este tema?

Todo lo que hay en lab-61-1 vuelve a los archivos iniciales y se limpia el terminal. Tu solución actual se perderá: no se puede deshacer.

Se restablecerá
  • main.py → código inicial
  • Historial del terminal y salida de pruebas
  • Cambios sin enviar
Se conservará
  • Mejor puntuación del lab
  • Tu XP y tu racha
  • Progreso de la lección y notas

Inicia sesión para ejecutar tu código.

Todas las clases se pueden leer gratis. Crea una cuenta o inicia sesión para ejecutar código, lanzar las pruebas y enviar este lab.

  • IDE en el navegador con terminal bash — sin instalar nada
  • Corrección instantánea, XP y tu lugar en la ruta
Crear una cuentaIniciar sesión
O
Continuar con GitHub