σμ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 2 · NumPy y pandas para datos de mercado›Tema 2.12·~40 minIntermedio

DatetimeIndex e indexación temporal

Posición en la rutaMódulo 2 de 11 · Tema 12 de 20
2.12 DatetimeIndex e indexación temporal
—Puntuación del lab— / 100XP total—Racha—

Las fechas no son cadenas de texto

Una serie de precios es una serie temporal: lo que importa es cuándo ocurrió cada precio. Las fechas leídas de un archivo son simples cadenas, y una cadena no sabe que marzo viene después de febrero ni que un lunes sigue a un domingo. Conviértelas con pd.to_datetime y usa el resultado como índice: un DatetimeIndex contiene marcas de tiempo reales que pandas puede ordenar, cortar, comparar y descomponer. Ordénalo siempre (sort_index()) para que la observación más antigua venga primero.

import pandas as pd

raw_dates = ["2026-03-04", "2026-03-02", "2026-03-03"]      # strings, in a messy order
closes = [102.0, 100.0, 101.0]

series = pd.Series(closes, index=pd.to_datetime(raw_dates), name="close").sort_index()
print(series)
# 2026-03-02    100.0
# 2026-03-03    101.0
# 2026-03-04    102.0
# Name: close, dtype: float64

print(isinstance(series.index, pd.DatetimeIndex))   # True

Construir un calendario

A menudo necesitas fechas que nadie te dio: una cuadrícula para comparar o los días de un backtest. pd.date_range(start, periods=n, freq="D") produce n días naturales consecutivos, y pd.bdate_range omite los fines de semana y da días hábiles. (No sabe nada de festivos.) El argumento freq fija el paso: "D" es un día, "B" un día hábil, "h" una hora.

# Four calendar days, then six business days (the weekend is skipped)
print(pd.date_range("2026-03-01", periods=4, freq="D").strftime("%a %d %b").tolist())
# ['Sun 01 Mar', 'Mon 02 Mar', 'Tue 03 Mar', 'Wed 04 Mar']

days = pd.bdate_range("2026-02-26", periods=6)
print(days.strftime("%a %d %b").tolist())
# ['Thu 26 Feb', 'Fri 27 Feb', 'Mon 02 Mar', 'Tue 03 Mar', 'Wed 04 Mar', 'Thu 05 Mar']

Seleccionar por fecha

Con un DatetimeIndex ordenado, .loc entiende fechas escritas como cadenas. Una cadena parcial como "2026-03" selecciona todo el mes, "2026" todo el año y "2026-03-04" un solo día. Un corte .loc["2026-03-04":"2026-03-06"] selecciona un rango y, a diferencia de un corte por posiciones, ambos extremos están incluidos. Los extremos no necesitan existir en los datos: las fechas de fin de semana simplemente no coinciden con nada, que es lo que quieres cuando pides «todo desde el uno del mes».

prices = pd.Series(
    [float(i) for i in range(20)],
    index=pd.bdate_range("2026-02-23", periods=20),   # Mon 23 Feb ... Fri 20 Mar
)

print(len(prices.loc["2026-03"]))      # 15   the business days of March in the data
print(prices.loc["2026-03-04"])        # 7.0  a single day

print(prices.loc["2026-03-04":"2026-03-06"])
# 2026-03-04    7.0
# 2026-03-05    8.0
# 2026-03-06    9.0
# Freq: B, dtype: float64

print(prices.loc["2026-03-01":"2026-03-03"].tolist())   # [5.0, 6.0]   Sunday the 1st matches nothing

Las partes de una fecha

Un DatetimeIndex expone las partes de cada fecha como atributos: year, month, day, dayofweek (el lunes es 0, el domingo 6). Cada una es un array con una entrada por fila, así que sirve como máscara o como clave de grupo. Así se pregunta «¿cuántas observaciones caen en cada día de la semana?» o «¿qué pasa los lunes?» sin bucle. Recuerda ordenar el índice antes: cortar un DatetimeIndex desordenado puede dar resultados sorprendentes o un error.

# The parts of the dates, one entry per row
print(prices.index.dayofweek[:7].tolist())   # [0, 1, 2, 3, 4, 0, 1]   Monday is 0
print(prices.index.month[:7].tolist())       # [2, 2, 2, 2, 2, 3, 3]

# How many observations fall on each weekday?
print(prices.groupby(prices.index.dayofweek).size().to_dict())   # {0: 4, 1: 4, 2: 4, 3: 4, 4: 4}

# What do the Mondays look like?
print(prices[prices.index.dayofweek == 0].tolist())   # [0.0, 5.0, 10.0, 15.0]
Cuidado con el final del rangoUna cadena de fecha sin hora significa medianoche. Con datos diarios, .loc["2026-03-04":"2026-03-06"] incluye el día 6, pero con datos intradía se detiene a las 00:00 del 6 y pierde todo el día. Comprueba la última marca de tiempo del resultado cuando tus datos sean más finos que un día.
  • pd.to_datetime(cadenas) crea un DatetimeIndex; sort_index() pone lo más antiguo primero; date_range y bdate_range construyen calendarios.
  • .loc["2026-03"] selecciona un mes, .loc["2026-03-04":"2026-03-06"] un rango con ambos extremos incluidos.
  • index.year, index.month, index.dayofweek dan las partes de cada fecha, para filtrar o agrupar sin bucles.

A continuación: el remuestreo, que convierte precios diarios en barras semanales, mensuales o más finas.

Lab: qué se califica

  • Construir una serie de precios con fechas con parse_prices25 pts
  • Seleccionar un mes con prices_in_month25 pts
  • Seleccionar un rango de fechas con prices_between25 pts
  • Contar las observaciones por día de la semana con count_by_weekday25 pts
Explorador · lab-45-1
▾ lab-45-1
…
bash · en el navegador
learner@quantcraft:~/lab-45-1$
Python aún no cargadoPythonLn 1, Col 1Spaces: 4UTF-8

¿Restablecer este tema?

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