Saltar a contenido

Indicadores y features

Qué vas a aprender

  • Qué es un indicador técnico y qué es una feature en este proyecto.
  • Por qué un indicador debe ser una función causal.
  • Qué son el warmup (calentamiento) y first_valid, con un ejemplo numérico calculado a mano.
  • Qué son las variantes entre motores y por qué no son errores.

Este capítulo es conceptual

El catálogo completo (386 descubiertos; 375 ejecutables por la API: 33 con fórmula canónica y paridad verificada y 342 por paso directo al motor sin garantías canónicas; 11 no ejecutables con motivo), los niveles de capacidad y más ejemplos numéricos están en la Parte IV · Indicadores.

De la barra al indicador

Un indicador transforma una serie de precios en otra serie que resume algo: la tendencia (medias móviles), el impulso (RSI), la volatilidad (ATR, Bollinger)… En el banco, a la serie calculada y lista para que la use una política se le llama feature. Una feature lleva, además de sus valores, metadatos: su especificación (FeatureSpec: indicador + parámetros + fuente), su first_valid_index y su máscara de validez.

flowchart LR
    P["close[0..T]"] --> I["Indicador<br/>EMA(periodo=3)"]
    I --> F["Feature<br/>valores + first_valid + máscara"]
    F --> POL["Política"]

Causalidad: solo el pasado

Una función es causal si el valor en la barra t depende únicamente de datos disponibles hasta t (inclusive). Una media móvil centrada, que usa barras futuras, no es causal: en un backtest daría señales que nadie podía conocer.

La forma más barata de engañarse

Un indicador no causal hace que cualquier estrategia parezca genial. Por eso el banco compara motores barra a barra: si uno de ellos «mirara el futuro», la paridad lo delataría.

Warmup y first_valid

Una media de 3 barras no puede calcularse con 2 barras. Las primeras posiciones de toda feature son no válidas: el periodo de calentamiento (warmup). El índice de la primera posición válida es first_valid_index.

Zona de warmup y first_valid de SMA20, EMA20, RSI14, ATR14 y ADX14

Figura 1. Cada indicador necesita un número distinto de barras antes de dar su primer valor válido (índices 0-based).

EMA de periodo 3 con semilla SMA, a mano

Serie de entrada: [1, 2, 3, 4, 5, 6]. Factor de suavizado α = 2 / (3 + 1) = 0,5.

t close Cálculo EMA
0 1 faltan datos null
1 2 faltan datos null
2 3 semilla = SMA(1,2,3) = 2 2
3 4 0,5·4 + 0,5·2 3
4 5 0,5·5 + 0,5·3 4
5 6 0,5·6 + 0,5·4 5

Resultado: [null, null, 2, 3, 4, 5], con first_valid_index = 2. Este es exactamente el golden del vertical G1 de la plataforma (ema_period3_golden.json, oráculo migration/baseline/oracle/ema_oracle.py).

Tres reglas que el banco aplica a rajatabla:

  1. Antes de first_valid no hay valor: es null/NaN, nunca cero. Un cero fabricaría una señal.
  2. La política no decide antes de tener todas sus features: first_decision_index es el máximo de los first_valid_index de todas las features que necesita. Antes, el objetivo es 0 con motivo REASON_WARMUP (que no es lo mismo que decidir estar plano).
  3. La ventana pedida debe cubrir el warmup: si no, la API responde 409 INSUFFICIENT_HISTORY en vez de inventar.

Warmup en un backtest real

En el backtest de P01 (cruce de EMAs 20/50) sobre NVDA diario 2024, la API devuelve warmup_bars: 49 y first_decision_index: 49: la EMA de 50 no es válida hasta la barra 49 (ver Tutorial).

Semillas y variantes

Dos implementaciones «de la misma EMA» pueden diferir en cómo arrancan: semilla SMA frente a primer valor, o empezar en period frente a period-1. No es un bug: es una definición distinta. El banco la llama VARIANT, la declara con un nombre y la mide.

RSI(14) sobre NVDA diario, ene–feb 2024 (respuesta real de la API)

Campo VectorTA Nautilus
provider.variant canonical nt_init_period_minus_1_scaled_0_1
first_valid_index 14 13
Último valor (2024-02-29) 72,92 70,68

La diferencia viene del calentamiento. Por eso la paridad compara desde la primera barra común y solo exige exactitud en señales, fills y equity; las features admiten tolerancias registradas con motivo en finazbench/features/compare.py.

Batch frente a stream

Un indicador puede calcularse de dos formas:

Modo Cómo Para qué
batch Se le da la serie entera y devuelve la serie entera Backtests rápidos, barridos
stream (incremental) Se le da una observación cada vez y devuelve el valor nuevo Simular el tiempo real, carril online

Ambos deben dar el mismo número barra a barra. Comprobarlo es parte de la paridad (carril NT_ONLINE, ver Carriles).

Resumen

  • Una feature es un indicador calculado con metadatos: especificación, first_valid y máscara.
  • Todo indicador debe ser causal; antes de first_valid no hay valor, y nunca se rellena con cero.
  • EMA(3) con semilla SMA sobre [1..6] da [null, null, 2, 3, 4, 5].
  • Las diferencias de semilla entre motores son VARIANT declaradas, no errores.

Para practicar

  1. Calcula a mano la EMA(2) con semilla SMA de [2, 4, 6, 8].
  2. Una política usa EMA(20) y EMA(50). ¿Cuál es su first_decision_index?
  3. ¿Por qué rellenar el warmup con ceros puede generar una operación falsa en la primera barra?