σμ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 8 · Modelos estocásticos y aprendizaje automático›Tema 8.8·~1 hAvanzado

Pipelines de scikit-learn para rendimientos

Posición en la rutaMódulo 8 de 11 · Tema 8 de 10
8.8 Pipelines de scikit-learn para rendimientos
—Puntuación del lab— / 100XP total—Racha—

Aprendizaje automático sobre rendimientos

El aprendizaje supervisado ajusta una función de las variables X al objetivo y. En finanzas el objetivo suele ser un rendimiento futuro y las variables son cosas conocidas de antemano: rendimientos pasados, volatilidad, volumen. scikit-learn ofrece una interfaz uniforme: todo modelo tiene fit(X, y) y predict(X). Una diferencia clave con los problemas de libro de texto es la relación señal/ruido: los rendimientos son casi puro ruido, así que incluso un buen modelo explica una fracción mínima, y una configuración descuidada encuentra patrones que no existen.

import numpy as np

returns = np.array([0.01, -0.02, 0.015, 0.005, -0.01, 0.02])
n_lags = 2

# Row i holds the two returns before the target; y[i] is the return that follows them
windows = np.lib.stride_tricks.sliding_window_view(returns, n_lags)
X, y = windows[:-1], returns[n_lags:]
print(X)
print(y)                                             # the targets are one step ahead of the features

Variables a partir de retardos

Las variables más simples de un rendimiento son los rendimientos anteriores. Construye una matriz de retardos: la fila i contiene returns[i : i + n_lags], y el objetivo es returns[i + n_lags], el valor siguiente. Una vista de ventana deslizante la da sin bucle. Todo lo de una fila debe conocerse en el momento de predecir, que es la regla de anticipación aplicada a un modelo: una variable desplazada una posición en el sentido equivocado dejaría al modelo ver la respuesta.

import numpy as np
from sklearn.linear_model import Ridge
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

# Pipeline: scale each feature, then a ridge regression (a linear model with a penalty on large coefficients)
pipe = Pipeline([("scale", StandardScaler()), ("model", Ridge(alpha=10.0))])
print([name for name, _ in pipe.steps])

rng = np.random.default_rng(1)
returns = np.zeros(400)
noise = rng.normal(0, 0.01, size=400)
for t in range(1, 400):
    returns[t] = 0.3 * returns[t - 1] + noise[t]                    # a series with a little memory

windows = np.lib.stride_tricks.sliding_window_view(returns, 3)
X, y = windows[:-1], returns[3:]
pipe.fit(X[:300], y[:300])                                          # fit on the first 300 rows
print(np.round(pipe.named_steps["model"].coef_, 4))                 # the last lag weighs most

Pipelines y fuga de información

Un Pipeline agrupa el escalador y el modelo de modo que fit aprende las estadísticas de escalado (media y desviación de cada variable) solo con las filas de entrenamiento y predict las aplica sin cambios a filas nuevas. Escalar todo el conjunto antes de dividirlo filtraría la media y dispersión del periodo de prueba al entrenamiento: el mismo sesgo de anticipación, en un lugar nuevo. En una serie temporal la división también es cronológica: entrenar con las filas tempranas, probar con las posteriores, nunca una mezcla aleatoria.

import numpy as np
from sklearn.linear_model import Ridge
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

def build_pipeline(alpha):
    return Pipeline([("scale", StandardScaler()), ("model", Ridge(alpha=alpha))])

rng = np.random.default_rng(1)
returns = np.zeros(600)
noise = rng.normal(0, 0.01, size=600)
for t in range(1, 600):
    returns[t] = 0.3 * returns[t - 1] + noise[t]

windows = np.lib.stride_tricks.sliding_window_view(returns, 3)
X, y = windows[:-1], returns[3:]
model = build_pipeline(10.0).fit(X[:400], y[:400])                  # chronological split: early rows to train
pred = model.predict(X[400:])                                       # later rows to test
print(round(float(np.mean(np.sign(y[400:]) == np.sign(pred))), 3))  # direction accuracy on unseen data

Juzgar el resultado con honestidad

Para una señal de trading, la dirección suele ser lo que importa, así que una puntuación simple es la precisión direccional: la proporción de días en que el rendimiento predicho y el real tienen el mismo signo. El 50 % es cara o cruz. Los predictores reales de rendimientos alcanzan el 51 al 53 %, y un 60 % en datos de prueba es más probablemente una fuga que un hallazgo. Compara con las referencias triviales (predecir siempre subida, predecir cero) antes de creer nada.

import numpy as np

y_true = np.array([0.01, -0.02, 0.015, -0.005, 0.02, -0.01])
y_pred = np.array([0.004, 0.001, 0.002, -0.001, 0.003, 0.002])        # the model is right on 4 of 6 signs

accuracy = float(np.mean(np.sign(y_true) == np.sign(y_pred)))
always_up = float(np.mean(np.sign(y_true) == 1))                      # the trivial baseline: always predict a rise
print(round(accuracy, 3), round(always_up, 3))                        # compare the model with the baseline
Modelos simples, validación honestaCon tanto ruido, los modelos lineales regularizados (ridge, lasso) suelen superar a los flexibles como árboles profundos o redes neuronales, que memorizan el periodo de entrenamiento. La penalización alpha es un mando que ajustar, pero en un periodo de validación, nunca en el de prueba. Los siguientes temas construyen las variables y la validación walk-forward que lo hacen honesto.
  • Una matriz de retardos (sliding_window_view) da variables a partir de los rendimientos previos a cada objetivo; todo lo de una fila debe conocerse al predecir.
  • Un Pipeline([("scale", StandardScaler()), ("model", Ridge(alpha=alpha))]) aprende el escalado solo con las filas de entrenamiento; divida cronológicamente, nunca al azar.
  • Puntúe la dirección (proporción de signos iguales) frente a referencias triviales; 51 al 53 % es realista, 60 % sugiere fuga; los modelos lineales regularizados convienen a datos ruidosos.

A continuación: la ingeniería de variables para datos financieros, construir mejores entradas que los rendimientos retardados en bruto.

Lab: qué se califica

  • Convertir una serie en variables con lag_matrix25 pts
  • Encadenar los pasos con build_pipeline25 pts
  • Entrenar con el pasado y predecir el resto con fit_predict25 pts
  • Puntuar las direcciones con direction_accuracy25 pts
Explorador · lab-109-1
▾ lab-109-1
…
bash · en el navegador
learner@quantcraft:~/lab-109-1$
Python aún no cargadoPythonLn 1, Col 1Spaces: 4UTF-8

¿Restablecer este tema?

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