Una ventana que se desliza
El precio de hoy significa poco por sí solo; los traders lo comparan con el pasado reciente. Una ventana móvil conserva las últimas n observaciones y avanza un paso cada vez, de modo que cada fecha recibe una estadística calculada con su propio pasado reciente: una media móvil, una volatilidad reciente, un máximo reciente. En pandas, series.rolling(n) describe la ventana y una estadística como .mean() la calcula en cada posición a la vez.
import pandas as pd
prices = pd.Series(
[100.0, 102, 101, 105, 107, 106, 110],
index=pd.bdate_range("2026-03-02", periods=7),
name="close",
)
moving_average = prices.rolling(3).mean()
print(moving_average.round(2).tolist())
# [nan, nan, 101.0, 102.67, 104.33, 106.0, 107.67]
print(prices.rolling(3).max().tolist()) # [nan, nan, 102.0, 105.0, 107.0, 107.0, 110.0] the 3-day highEl comienzo de la serie
Las primeras n - 1 posiciones aún no tienen una ventana completa, así que el resultado es NaN. Es honesto: la media de dos precios no es una media de 3 días. Si de verdad quieres un valor antes, min_periods=1 calcula con lo disponible, y expanding() usa todo desde el inicio en lugar de una ventana fija. Las estadísticas que necesitan varios puntos, como la desviación típica, son NaN hasta que llegan suficientes observaciones. Una serie que ya empieza con NaN, como los rendimientos simples, retrasa un paso la primera ventana válida.
# min_periods=1: use whatever is available at the start
print(prices.rolling(3, min_periods=1).mean().round(2).tolist()) # [100.0, 101.0, 101.0, 102.67, 104.33, 106.0, 107.67]
# expanding(): everything since the first day, not a fixed window
print(prices.expanding().mean().round(2).tolist()) # [100.0, 101.0, 101.0, 102.0, 103.0, 103.5, 104.43]
# Rolling volatility of the returns: the first return is NaN, so three returns exist only from the 4th day
returns = prices.pct_change()
print(returns.rolling(3).std().round(4).tolist()) # [nan, nan, nan, 0.0249, 0.0248, 0.0246, 0.0237]De las ventanas a las señales
Las estadísticas móviles se convierten en señales de trading cuando se comparan. Un z-score dice a cuánta distancia está el precio de hoy de su propia media reciente, en unidades de su desviación típica reciente: (price - rolling mean) / rolling std. Construye el objeto móvil una vez (r = prices.rolling(3)) y úsalo dos veces. Un cruce de medias móviles compara una media rápida con una lenta: mientras la rápida está por encima, la tendencia reciente es alcista. Una comparación da booleanos, y astype("int64") los convierte en una señal 0/1. Las comparaciones con NaN son False, así que la señal es 0 hasta que existen ambas medias.
# z-score of each price against its own 3-day window
rolling = prices.rolling(3)
zscore = (prices - rolling.mean()) / rolling.std()
print(zscore.round(2).tolist()) # [nan, nan, 0.0, 1.12, 0.87, 0.0, 1.12]# Moving-average crossover: 1 while the 2-day average is above the 4-day average
fast = prices.rolling(2).mean()
slow = prices.rolling(4).mean()
signal = (fast > slow).astype("int64")
print(signal.tolist()) # [0, 0, 0, 1, 1, 1, 1]
# Trade on the next day: the signal of today's close cannot be traded before tomorrow
print(signal.shift(1).fillna(0).astype("int64").tolist()) # [0, 0, 0, 0, 1, 1, 1]center=True pone la fila actual en medio de la ventana y usa precios futuros: queda genial en un gráfico y no se puede operar. Una señal calculada con el cierre de hoy debe aplicarse mañana, de ahí shift(1).series.rolling(n).mean()(ostd(),max()...) calcula una estadística sobre las últimasnobservaciones en cada posición.- Las primeras
n - 1entradas sonNaN;min_periodsyexpanding()lo cambian a propósito. - Los z-scores y los cruces de medias móviles convierten ventanas en señales; desplaza una señal antes de operarla y evita
center=True.
A continuación: el manejo de datos faltantes, qué hacer con los valores NaN que las tablas de precios reales siempre contienen.
Lab: qué se califica
- Suavizar los precios con
moving_average25 pts - Medir el riesgo reciente con
rolling_volatility25 pts - Estandarizar cada precio frente a su ventana con
rolling_zscore25 pts - Convertir dos medias en una señal con
ma_crossover25 pts