Rentabilidades en código: simples frente a logarítmicas, rentabilidades acumuladas, rentabilidad y volatilidad anualizadas, y ventanas móviles
Calcula rentabilidades simples y logarítmicas en pandas, compónlas correctamente, anualiza la rentabilidad y la volatilidad, y construye estadísticas móviles.
Qué aprenderás
- Cómo calcular rentabilidades simples y logarítmicas a partir de una serie de cierres y cuándo es cada una la herramienta adecuada.
- Por qué las rentabilidades simples deben componerse con un producto, mientras que las logarítmicas simplemente se suman.
- Cómo anualizar una rentabilidad media diaria y una desviación típica diaria, y qué supone la regla de la raíz cuadrada del tiempo.
- Cómo producen las ventanas móviles estadísticas variables en el tiempo, como la volatilidad a 20 días, y por qué las primeras filas están vacías.
Explicación
Una rentabilidad simple es la variación porcentual del precio, rt = (Pt − Pt−1) ÷ Pt−1, en pandas r = df["close"].pct_change(). Una rentabilidad logarítmica es el logaritmo natural del cociente de precios, ℓt = ln(Pt ÷ Pt−1), en código np.log(df["close"]).diff(). Ambas empiezan con un NaN. Para movimientos pequeños las dos son casi idénticas; para movimientos grandes divergen (una rentabilidad simple del −50% es una rentabilidad logarítmica del −69.3%).
Composición. A lo largo de varios periodos, las rentabilidades simples se multiplican: total = (1 + r1)(1 + r2)…(1 + rn) − 1. Las logarítmicas se suman: rentabilidad logarítmica total = ℓ1 + ℓ2 + … + ℓn, y al convertir de vuelta se obtiene la rentabilidad simple total = exp(suma) − 1. Sumar rentabilidades simples es un error, y el error crece con la volatilidad: +10% seguido de −10% suma 0%, pero en realidad deja un −1%. Una serie de rentabilidad acumulada es (1 + r).cumprod() − 1; una curva de capital a partir de €10,000 es 10_000 * (1 + r).cumprod(); con rentabilidades logarítmicas, np.exp(lr.cumsum()).
Cuándo usar cada una. Las logarítmicas, para agregar a lo largo del tiempo y para la estadística; las simples, siempre que cambie dinero de manos o se combinen activos, porque la rentabilidad de una cartera es una suma ponderada de rentabilidades simples. Comunica los resultados a las personas en porcentajes simples.
Anualizar. Por convención se suponen 252 días de negociación al año para la renta variable (la cifra real varía ligeramente según la bolsa y el año; indica la convención que usas). La rentabilidad media diaria × 252 es la rentabilidad anualizada aritmética, y la CAGR (compound annual growth rate, tasa de crecimiento anual compuesta, definida en el curso Trading sistemático y backtesting) es (final ÷ inicial)1 ÷ años − 1, que es lo que deberías comunicar para un backtest. La volatilidad es la desviación típica de las rentabilidades; escala con la raíz cuadrada del tiempo, así que la volatilidad anual ≈ desviación típica diaria × √252 ≈ diaria × 15.87. Para datos mensuales usa 12 y √12; para semanales, 52 y √52. La regla de la raíz cuadrada supone rentabilidades independientes, algo que las series con tendencia incumplen; trátala como una convención.
Ventanas móviles. r.rolling(20).std() * np.sqrt(252) da la volatilidad anualizada de los 20 días más recientes, recalculada en cada fila. Las primeras 19 filas son NaN porque la ventana no está completa (min_periods puede relajar esto). expanding() usa todos los datos hasta cada fila (el máximo acumulado del capital para el drawdown en la lección 9). Ambas miran solo hacia atrás, por lo que por construcción están libres de sesgo de anticipación.
Ejemplo práctico
Ejemplo hipotético: cuatro cierres de una acción, €100.00, €105.00, €100.80, €105.84; sin costes, dividendos ni impuestos.
Rentabilidades simples: (105 − 100) ÷ 100 = +5.00%; (100.80 − 105) ÷ 105 = −4.00%; (105.84 − 100.80) ÷ 100.80 = +5.00%.
Rentabilidades logarítmicas: ln(1.05) = 0.04879; ln(0.96) = −0.04082; ln(1.05) = 0.04879. Suma = 0.05676. exp(0.05676) − 1 = 0.0584, es decir, +5.84%.
Comprobación: 1.05 × 0.96 × 1.05 = 1.0584 → +5.84%, y 105.84 ÷ 100 − 1 = 5.84%. Sumar las rentabilidades simples daría 6.00%, una sobrestimación de 0.16 puntos en tres días: €10,000 se convierten en €10,584, no en €10,600.
Código: r = c.pct_change(); total = (1 + r.dropna()).prod() - 1 devuelve 0.0584. r.rolling(3).mean() coloca (0.05 − 0.04 + 0.05) ÷ 3 = 2.00% en la última fila y NaN antes.
Anualización de una muestra hipotética más larga: si las rentabilidades diarias tienen una media del 0.04% y una desviación típica del 1.2%, la rentabilidad anualizada aritmética es 0.0004 × 252 = 10.08% y la volatilidad anualizada es 0.012 × 15.87 = 19.05%.
Error frecuente
r.sum() como rentabilidad del periodo. Eso ignora la composición y sobrestima los resultados en series volátiles, de forma drástica en los productos apalancados. Usa (1 + r).prod() − 1 para rentabilidades simples, o suma las rentabilidades logarítmicas y aplica la exponencial.Actividad práctica
En papel: cierres de €50.00, €48.00, €50.40, €49.392 (hipotético). (a) Calcula las tres rentabilidades simples. (b) Calcula las tres rentabilidades logarítmicas usando ln(0.96) = −0.04082, ln(1.05) = 0.04879 y ln(0.98) = −0.02020. (c) Da la rentabilidad total por composición y sumando los logaritmos, y compárala con la suma ingenua de las rentabilidades simples. (d) Si otra serie muestra una desviación típica diaria del 1.5%, indica su volatilidad anualizada con 252 días y explica por qué multiplicar por 252 sería un error.
Mostrar solución
(a) 48 ÷ 50 − 1 = −4.00%; 50.40 ÷ 48 − 1 = +5.00%; 49.392 ÷ 50.40 − 1 = −2.00%.
(b) −0.04082, +0.04879, −0.02020; suma = −0.01223.
(c) Compuesta: 0.96 × 1.05 × 0.98 = 0.98784 → −1.216%. A partir de los logaritmos: exp(−0.01223) − 1 = −1.216%, y 49.392 ÷ 50 − 1 = −1.216% lo confirma. La suma ingenua da −4 + 5 − 2 = −1.00%, lo que subestima la pérdida.
(d) Volatilidad anualizada = 1.5% × √252 = 1.5% × 15.87 = 23.8%. Multiplicar por 252 daría 378%, porque confunde la regla de escalado de las medias (lineal en el tiempo) con la de las desviaciones típicas (raíz cuadrada del tiempo).
Limitaciones: la regla de √252 supone rentabilidades diarias independientes; las series reales con autocorrelación tienen una volatilidad anual verdadera distinta.
Ideas clave
pct_change()da rentabilidades simples,np.log(c).diff()da rentabilidades logarítmicas; ambas dejan unNaNen la primera fila.- Compón las rentabilidades simples con un producto; suma las logarítmicas y aplica la exponencial; nunca sumes rentabilidades simples.
- Anualiza las medias con × 252 y las desviaciones típicas con × √252, indica la convención y comunica la CAGR en los backtests.
- Las ventanas móviles y expansivas miran solo hacia atrás, producen
NaNhasta estar completas y usan por defecto la desviación típica muestral.
Siguiente paso
La lección 6 programa los indicadores estándar como funciones vectorizadas, SMA, EMA, RSI, ATR y bandas de Bollinger, y muestra cómo verificarlos frente a una plataforma de gráficos.
Autoevaluación
Responde a las preguntas y luego comprueba tus respuestas. Puedes volver a intentarlo tantas veces como quieras.
Autoevaluación automática para tu propio repaso. Tus respuestas se comprueban en tu navegador y no las vemos ni evaluamos. No es un examen ni una titulación.
Tu progreso
«Completada» solo significa que marcaste la lección como terminada. No es una prueba de tu comprensión. El progreso y las notas se guardan solo en este navegador y en este dispositivo, no en una cuenta.