σμ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 7 · Investigación de alfa y riesgo›Tema 7.8·~1 hAvanzado

Modelos ARIMA

Posición en la rutaMódulo 7 de 11 · Tema 8 de 9
7.8 Modelos ARIMA
—Puntuación del lab— / 100XP total—Racha—

Una serie que se recuerda a sí misma

Muchas series llevan información sobre su propio futuro. Los diferenciales de tipos, la volatilidad y la brecha entre dos precios relacionados tienden a volver hacia un nivel en vez de vagar libremente. Los modelos ARIMA lo capturan con tres ideas: I, diferenciar la serie para hacerla estacionaria; AR, regresarla sobre sus propios retardos; MA, usar los errores de pronóstico recientes. Los rendimientos de las acciones casi no muestran esa memoria, así que ARIMA pertenece a series persistentes o de reversión a la media.

import numpy as np

prices = np.array([100.0, 101.5, 103.2, 104.1, 106.0, 107.2])

print(np.diff(prices))              # first differences: the changes             [1.5 1.7 0.9 1.9 1.2]
print(np.diff(prices, n=2))         # second differences: the change of the changes
print(np.diff(np.log(prices)))      # the differenced log price is the log return

Diferenciación y autocorrelación

Los precios vagan y no tienen media estable; sus cambios a menudo sí. Tomar la primera diferencia (orden d = 1) elimina una tendencia, una segunda (d = 2) una tendencia curva. La función de autocorrelación (ACF) muestra entonces la memoria: su valor en el retardo k es la correlación de la serie consigo misma k pasos antes, sum((x[t] - m) * (x[t+k] - m)) / sum((x[t] - m)**2). Una ACF que decae despacio sugiere un modelo AR; una ACF cercana a cero en todos los retardos significa que no hay nada que pronosticar.

# The ACF of a persistent series decays slowly; the ACF of noise is near zero
import numpy as np

def acf(series, lags):
    dev = series - series.mean()
    total = np.sum(dev ** 2)
    return np.array([np.sum(dev[:len(series) - k] * dev[k:]) / total for k in range(1, lags + 1)])

rng = np.random.default_rng(1)
noise = rng.normal(size=500)
persistent = np.empty(500)
persistent[0] = 0.0
for t in range(1, 500):
    persistent[t] = 0.8 * persistent[t - 1] + noise[t]           # an AR(1) with phi = 0.8
print(np.round(acf(persistent, 4), 3))                           # decays slowly: 0.74, 0.58, 0.48, 0.39 in this sample
print(np.round(acf(noise, 4), 3))                                # all near 0
# Differencing a trending series makes its mean stable
import numpy as np

rng = np.random.default_rng(6)
trend = 100 + 0.5 * np.arange(200) + rng.normal(0, 1, size=200).cumsum()          # a trending random walk
changes = np.diff(trend)
print(round(float(trend[:100].mean()), 1), round(float(trend[100:].mean()), 1))     # the level drifts: the halves differ a lot
print(round(float(changes[:100].mean()), 2), round(float(changes[100:].mean()), 2))   # the changes have a similar mean in both halves

Ajustar un AR(1) y pronosticar

Un AR(1) dice x[t] = c + phi * x[t-1] + ruido. Es una regresión lineal de cada valor sobre el anterior: phi es la pendiente y c la ordenada, con las mismas sumas que la beta del tema CAPM. El pronóstico es recursivo: el primer paso es c + phi * last, y cada siguiente usa el pronóstico anterior. Para |phi| < 1 los pronósticos convergen a la media de largo plazo c / (1 - phi), con velocidad fijada por phi: una serie de reversión a la media.

import numpy as np

def fit_ar1(series):
    a, b = series[:-1], series[1:]
    phi = np.sum((a - a.mean()) * (b - b.mean())) / np.sum((a - a.mean()) ** 2)
    return float(b.mean() - phi * a.mean()), float(phi)

def forecast_ar1(last, c, phi, steps):
    out, value = [], last
    for _ in range(steps):
        value = c + phi * value
        out.append(value)
    return np.array(out)

rng = np.random.default_rng(3)
x = np.empty(400)
x[0] = 2.0
for t in range(1, 400):
    x[t] = 0.5 + 0.75 * x[t - 1] + rng.normal(0, 0.3)             # true c = 0.5, phi = 0.75, mean 2.0
c, phi = fit_ar1(x)
print(round(c, 3), round(phi, 3))
print(np.round(forecast_ar1(4.0, c, phi, 5), 3), round(c / (1 - phi), 3))
Pronosticar no es operarUn phi estadísticamente significativo en un diferencial no garantiza beneficio: importan los costes, el tamaño del movimiento frente al ruido y la inestabilidad de la estimación. Mantén la disciplina habitual: ajustar en un periodo, pronosticar el siguiente y comparar con el pronóstico ingenuo de «sin cambio». Un modelo que no lo supera no ha encontrado nada.
  • ARIMA = diferenciación (I) + autorregresión (AR) + errores pasados (MA); diferenciar convierte una serie con tendencia en estacionaria.
  • La ACF en el retardo k es la correlación de la serie consigo misma k pasos antes; un decaimiento lento sugiere un modelo AR.
  • Un ajuste AR(1) es una regresión de x[1:] sobre x[:-1]; los pronósticos se alimentan entre sí y convergen a c / (1 - phi) si |phi| < 1; supera siempre el pronóstico «sin cambio».

A continuación: los modelos de volatilidad GARCH, pronosticar no el nivel de los rendimientos sino la violencia con que se mueven.

Lab: qué se califica

  • Quitar la tendencia con difference25 pts
  • Medir la memoria con acf25 pts
  • Ajustar el modelo con fit_ar125 pts
  • Mirar hacia delante con forecast_ar125 pts
Explorador · lab-100-1
▾ lab-100-1
…
bash · en el navegador
learner@quantcraft:~/lab-100-1$
Python aún no cargadoPythonLn 1, Col 1Spaces: 4UTF-8

¿Restablecer este tema?

Todo lo que hay en lab-100-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