σμ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.4·~45 minIntermedio

Contrastes de hipótesis: la prueba t

Posición en la rutaMódulo 3 de 11 · Tema 4 de 12
3.4 Contrastes de hipótesis: la prueba t
—Puntuación del lab— / 100XP total—Racha—

¿Es real el rendimiento medio?

Un backtest muestra un rendimiento medio de +0,14 % al día. ¿Es buena la estrategia o tuvo suerte? Los rendimientos son ruidosos, así que toda muestra tiene una media, e incluso una estrategia de cara o cruz la tiene positiva la mitad de las veces. Una prueba de hipótesis hace una pregunta precisa: si la media verdadera fuera mu0 (normalmente 0), ¿cuán sorprendente sería una media muestral tan alejada de mu0? La respuesta es un valor p. Un valor p pequeño dice que los datos serían muy improbables bajo la hipótesis de que «no pasa nada».

t = (mean - mu0) / (s / sqrt(n)) p = P(|Z| > |t|)

El estadístico t mide la media en unidades de su propia incertidumbre. La incertidumbre de una media es el error estándar s / sqrt(n): disminuye al crecer la muestra, por eso más datos hacen más convincente la misma media. Reescalar todos los rendimientos cambia por igual la media y el error estándar, así que t no cambia. Como regla práctica, un |t| superior a 2 difícilmente es suerte.

import math
import numpy as np

returns = np.array([0.004, -0.002, 0.001, 0.003, -0.004, 0.002, 0.006, -0.001, 0.005, 0.002, 0.003, -0.002])

n = len(returns)
mean = returns.mean()
std_error = returns.std(ddof=1) / math.sqrt(n)         # the uncertainty of the mean
t = mean / std_error                                   # testing against mu0 = 0

print(round(mean, 5), round(std_error, 6))             # 0.00142 0.000892   the mean is only 1.6 standard errors from 0
print(round(t, 3))                                     # 1.589

De t al valor p

Bajo la hipótesis nula, t se comporta como una normal estándar cuando la muestra es grande, así que el valor p bilateral es la probabilidad de caer a más de |t| de 0 en cualquier dirección: erfc(|t| / sqrt(2)). Con t = 1,59 es el 11 %: un resultado así de bueno ocurre una vez de cada nueve por azar, así que no podemos afirmar una ventaja real. El umbral habitual es el 5 % (|t| = 1,96). Para muestras pequeñas la referencia correcta es la t de Student, de colas más gruesas, por lo que el valor p normal es algo demasiado pequeño; con menos de 30 puntos usa una tabla t de verdad.

p_value = math.erfc(abs(t) / math.sqrt(2))
print(round(p_value, 4))                      # 0.1121   an outcome this good happens by chance about 1 time in 9

print(round(math.erfc(1.96 / math.sqrt(2)), 4))   # 0.05     |t| = 1.96 is the usual 5% limit

# Testing against another value: is the mean different from 0.2% a day?
t_other = (mean - 0.002) / std_error
print(round(t_other, 3), round(math.erfc(abs(t_other) / math.sqrt(2)), 3))   # -0.654 0.513

Intervalos de confianza y muestras pareadas

Un intervalo de confianza dice más que una prueba sí/no: media -/+ 1,96 * error estándar es un rango que contiene la media verdadera alrededor del 95 % de las veces. Si el intervalo contiene 0, la media no es significativa al 5 %. Nuestro intervalo, de -0,03 % a +0,32 % diario, cruza el cero y es ancho comparado con la media. Para comparar dos estrategias medidas en los mismos días, contrasta sus diferencias diarias con 0. El emparejamiento elimina el ruido que ambas comparten (los días buenos y malos del mercado), así que detecta una ventaja mucho más nítidamente que dos pruebas separadas.

low, high = mean - 1.96 * std_error, mean + 1.96 * std_error
print(round(low, 5), round(high, 5))           # -0.00033 0.00316   the interval contains 0: not significant at 5%

# Paired: the same six days for two strategies
a = np.array([0.004, -0.002, 0.001, 0.003, -0.004, 0.002])
b = np.array([0.002, -0.003, 0.000, 0.001, -0.002, 0.0])
d = a - b
t_paired = d.mean() / (d.std(ddof=1) / math.sqrt(len(d)))
print(round(d.mean(), 5), round(t_paired, 3))   # 0.001 1.581   a daily edge of 0.1%, but only 6 days
# Same mean and spread, four times the data: t doubles and the p-value collapses
spread = returns.std(ddof=1)
for n in (12, 48):
    t_n = mean / (spread / math.sqrt(n))
    print(n, round(t_n, 3), round(math.erfc(abs(t_n) / math.sqrt(2)), 4))
# 12 1.589 0.1121
# 48 3.178 0.0015
Significativo no es importante, y muchas pruebas hacen trampaUna ventaja minúscula puede ser muy significativa con suficientes datos, y una grande puede no serlo con pocos. Lee siempre el tamaño del efecto junto al valor p. Y si pruebas 100 estrategias, unas 5 pasarán al 5 % solo por suerte: cuantas más variantes pruebes sobre los mismos datos, menos significa un valor p aislado.
  • t = (mean - mu0) / (s / sqrt(n)): la media en unidades de su error estándar s / sqrt(n); más datos, |t| mayor.
  • El valor p bilateral es erfc(|t| / sqrt(2)) para muestras grandes; |t| > 1,96 significa p < 5 %; un intervalo mean -/+ 1,96 * se que contiene 0 significa no significativo.
  • Compara estrategias en los mismos días con el estadístico t de las diferencias diarias; cuidado con probar muchas variantes.

A continuación: la regresión lineal (MCO), para ajustar una recta que explique un rendimiento con otro.

Lab: qué se califica

  • Medir la media en unidades de su ruido con t_statistic25 pts
  • Convertir t en un valor p con two_sided_p25 pts
  • Acotar la media verdadera con confidence_interval25 pts
  • Comparar dos estrategias día a día con paired_t_statistic25 pts
Explorador · lab-57-1
▾ lab-57-1
…
bash · en el navegador
learner@quantcraft:~/lab-57-1$
Python aún no cargadoPythonLn 1, Col 1Spaces: 4UTF-8

¿Restablecer este tema?

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