Indicadores móviles para datos en streaming
Ene. 21, 2026
Motivación
Las aplicaciones financieras dependen de indicadores para tomar decisiones. Normalmente, estos indicadores se calculan a partir de datos de series temporales. El enfoque más común es calcular el indicador desde cero cada vez que se añade un nuevo punto de datos. Este enfoque parece simple y fácil de implementar, pero no es eficiente.
En el contexto de este artículo, un indicador móvil para datos en streaming es una métrica que mantiene memoria de cálculos anteriores para facilitar la actualización de la medición cuando llega un nuevo valor. Para introducir el concepto, el cálculo de promedios móviles se utiliza como ejemplo, estimando el número de operaciones requeridas y comparando esa métrica para ambos enfoques: calcular desde cero y usar un indicador móvil.
Descripción
El promedio móvil es un indicador ampliamente utilizado en finanzas para suavizar datos y identificar tendencias. Se calcula como el promedio de los últimos $n$ valores en una serie temporal.
$$\text{MA}(t, n) = \frac{1}{n} \sum_{i=t - n + 1}^{t} x_i$$
Cuando llega un nuevo valor, podemos calcular el promedio móvil usando la misma fórmula, simplemente desplazando la ventana hacia adelante una posición.
$$\text{MA}(t + 1, n) = \frac{1}{n} \sum_{i=t - n + 2}^{t+1} x_i$$
Una alternativa es eliminar el primer valor de la ventana, agregar el nuevo valor a la suma acumulada y dividir por $n$, como se muestra a continuación.
Dado:
$$S_t = \sum_{i = t - n + 1}^{t} x_i$$
$$x_{\text{prev}} = x_{t - n + 1}$$
Entonces:
$$\text{MA}(t + 1, n) = \frac{1}{n} [S_t - x_{\text{prev}} + (x_{t + 1})]$$
Rendimiento
Evaluemos el número de operaciones requeridas:
- Método 1: Cada paso requiere $n - 1$ sumas y una división. Para $t$ pasos, el número total de operaciones es $tn$.
- Método 2: El primer paso requiere $n$ operaciones. Cada paso subsiguiente requiere solo $3$ operaciones: una para restar el valor más antiguo, una para sumar el nuevo valor, y una para la división por $n$. El total es $n + 3(t - 1) = n + 3t - 3$.
Si el promedio móvil con $n = 10$ y $t = 252$ (días hábiles en un año), el rendimiento del segundo método es aproximadamente $3x$. En otro ejemplo, si $n = 90$ y $t = 1260$ (días hábiles para 5 años), el rendimiento del segundo método es aproximadamente $29x$.
Implementación
A continuación se muestra una definición de clase para el indicador de
promedio móvil. Se inicializa con el número de períodos. Tiene dos
métodos: update y get. El primero se usa para incluir un nuevo
valor y devuelve el promedio móvil actualizado. El segundo se usa para
consultar el valor del promedio móvil en cualquier momento.
class MA {
public:
MA(size_t periods);
double update(double value);
double get() { return m_len < m_periods
? NAN : m_accum / m_periods; }
private:
double m_accum = 0.0;
size_t m_periods;
size_t m_len = 0;
size_t m_pos = 0; // posición actual en buffer circular
std::vector<double> m_prevs; // array de n-períodos
};
La implementación de update se muestra a continuación. Durante las primeras
actualizaciones, incrementa m_len hasta que alcanza m_periods. En ese
momento, el promedio móvil se vuelve válido. En cada actualización, value
se suma a m_accum y se almacena en el buffer circular m_prevs. El valor
más antiguo se resta de m_accum cuando sale de la ventana.
double MA::update(double value) {
if (m_len < m_periods) {
++m_len;
} else {
m_accum -= m_prevs[m_pos];
}
m_prevs[m_pos] = value;
m_accum += value;
m_pos = (m_pos + 1) % m_periods;
return get();
}
Una implementación de estos conceptos está disponible en
ta-zig, una biblioteca de Zig que
proporciona indicadores de análisis técnico diseñados para datos en
streaming. Otro ejemplo también está desarrollado en la librería
pybottrader que
proporciona una clase Indicator implementado en C++ con interfaz para
Python.
Ambas librerías implementan el patrón de indicador móvil usando buffers circulares, manteniendo solo una ventana de valores necesarios en memoria, e incluyen indicadores comunes como promedios móviles, MACD, RSI, Bandas de Bollinger, y otros.
Discusión
El enfoque de indicador móvil es conveniente cuando se procesan datos en streaming a alta frecuencia, como datos de ticks o feeds en tiempo real, donde recalcular desde cero cada nuevo punto de datos sería costoso. Es ventajoso en escenarios con series temporales largas donde el número de actualizaciones excede significativamente el tamaño de la ventana, en entornos con restricciones de memoria donde almacenar el historial completo es impracticable, y en aplicaciones sensibles a la latencia como trading algorítmico o gestión de riesgos.
Sin embargo, el enfoque puede ser menos conveniente en escenarios de procesamiento por lotes donde los indicadores se calculan solo periódicamente, como instantáneas hourly o diarias, porque la sobrecarga de mantener estado puede no justificar los ahorros marginales. También puede ser inconveniente cuando la depuración y auditoría requieren verificar resultados mediante recomputación independiente. En lenguajes interpretados de alto nivel, la sobrecarga de implementación puede dominar cualquier ahorro computacional, y cuando el período de calentamiento es significativo relativo al número total de actualizaciones, los beneficios de la computación incremental se reducen.