Saltar a contenido

El catálogo de 386 indicadores

Si preguntas al banco de pruebas «¿cuántos indicadores tienes?», la respuesta honesta tiene varios números: 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. Este capítulo explica de dónde salen, cómo se consulta el catálogo y cómo se lee la ficha de un indicador, tanto de uno registrado por el proyecto (rsi) como de uno que solo existe en su motor (alma).

Qué vas a aprender

  • Cómo se construye el catálogo por introspección de los dos motores.
  • Qué significan 386, 346, 36, 15, 39, 375, 33, 342 y 11.
  • Cómo consultar el catálogo con GET /v1/indicators y sus filtros.
  • Cómo pedir ayuda con GET /v1/help y GET /v1/help/{name}.
  • Cómo leer la tabla docs/INDICATORS.md.
  • La diferencia práctica entre una ficha registrada y una solo de motor.

1. De dónde salen los 386

flowchart LR
    VTA[vector_ta 0.2.8<br/>funciones batch<br/>+ clases *Stream] --> CAT[finazbench/features/catalog.py<br/>introspección + sonda]
    NT[nautilus_trader 1.231.0<br/>subclases de Indicator<br/>update_raw / handle_bar] --> CAT
    REG[registro del proyecto<br/>39 primitivas] --> CAT
    CAT --> API[GET /v1/indicators]
    CAT --> MD[docs/INDICATORS.md<br/>tools/list_indicators.py]

El catálogo es la unión de lo que exponen los motores instalados más las primitivas del proyecto, con los nombres de ambos motores fusionados en una sola entrada cuando son el mismo indicador (por ejemplo, rsi agrupa vector_ta.rsi, RsiStream y RelativeStrengthIndex de Nautilus).

Cifra Qué cuenta
386 entradas del catálogo (unión de motores + proyecto)
346 entradas con carril VectorTA (batch y/o stream)
36 entradas con carril Nautilus (nativo y/o stream)
15 entradas expuestas por ambos motores
39 primitivas registradas del proyecto (fórmula canónica, paridad, aprobación)
347 entradas solo de motor (386 − 39): registered: false, nivel discovered
375 ejecutables por POST /v1/indicators (medido por tools/probe_indicators.py)
33 …de ellas, en modo canónico (execution_mode: canonical): primitivas registradas
342 …de ellas, por paso directo al motor (engine_passthrough): 323 con VectorTA y 21 con Nautilus (2 en ambos)
11 no ejecutables, con not_computable_reason: 6 primitivas que leen series derivadas o paneles y 5 indicadores de motor

Las 15 que tienen los dos motores

sma, ema, rma, rsi, bbands, atr, donchian, wma, hma, macd, keltner_sma, stochrsi, dmi, psychological_line y vertical_horizontal_filter. Que ambos motores tengan un nombre no implica que calculen lo mismo: ver las variantes en el capítulo de motores.

386 no son 386 cálculos soportados

Leer «386 indicadores» como «386 cálculos con garantías» es un error factual: solo 33 tienen fórmula canónica y paridad; los 342 de paso directo son «lo que diga el motor». Y leer «39 aprobados» como «aprobados para producción» es uno peor: ninguno lo está (production: false). El capítulo siguiente explica los niveles.


2. Consultar el catálogo: GET /v1/indicators

Arranca la API del banco y apunta a ella:

docker compose --profile bench-api up -d bench-api   # Swagger: http://localhost:8000/docs
BASE=http://localhost:8000

# Catálogo completo: count / total / catalog_size
curl -sS "$BASE/v1/indicators" | jq '.payload | {count, total, catalog_size}'

# Solo los que tienen carril en VectorTA y están registrados
curl -sS "$BASE/v1/indicators?engine=vectorta&registered=true" | jq '.payload.count'

# Búsqueda por subcadena en nombre y descripción
curl -sS "$BASE/v1/indicators?q=bollinger" | jq '.payload.indicators[] | {name, both_engines}'

# Las 39 primitivas aprobadas (33 ejecutables en modo canónico)
curl -sS "$BASE/v1/indicators?approved=true" | jq '.payload.count'

# Cuántos calcula la API y por qué modo
curl -sS "$BASE/v1/indicators" | jq '.payload | {computable_via_api, capability_counts}'
curl -sS "$BASE/v1/indicators?mode=passthrough" | jq '.payload.total'   # 347 (342 ejecutables)
Filtro Valores Efecto
engine all, vectorta, nautilus entradas con carril en ese motor
registered all, true, false primitivas del proyecto frente a solo-motor
verified booleano solo las verificadas por tests
approved booleano solo las aprobadas (benchmark + research)
mode all, canonical, passthrough primitivas registradas frente a entradas de paso directo
q texto subcadena en nombre y descripción

Cada entrada lleva su bloque capability y el payload trae capability_counts, de modo que un cliente nunca tiene que adivinar qué es ejecutable. Hay respuestas reales guardadas en examples/api/ (08_indicators_catalog.response.json, 11_indicators_catalog_nautilus.response.json, 16_indicators_catalog_approved.response.json).


3. Pedir ayuda: GET /v1/help

curl -sS "$BASE/v1/help"                 # índice de temas
curl -sS "$BASE/v1/help/rsi"  | jq       # indicador registrado
curl -sS "$BASE/v1/help/alma" | jq       # indicador solo de motor
curl -sS "$BASE/v1/help/P01"  | jq       # estrategia (template)

El índice tiene 417 temas = 39 primitivas + 347 indicadores solo de motor + 31 templates de estrategia (total: 417 en examples/api/12_help_index.response.json).


4. Dos fichas, dos mundos

4.1 rsi: una primitiva registrada

Extracto de examples/api/13_help_indicator_rsi.response.json:

{
  "id": "rsi",
  "kind": "indicator",
  "summary": "Wilder RSI from the RMA of gains and losses over the first n differences; flat = 50, gains only = 100, losses only = 0.",
  "project": {"registered": true, "primitive": "rsi", "phase": "A"},
  "inputs": ["close"], "outputs": ["rsi"],
  "first_valid_rule": "period",
  "params": [{"name": "period", "type": "int", "required": true, "example": 14}],
  "capability": {
    "level": "approved", "computable_via_api": true,
    "evidence": {"feature_fidelity": "tests/features/test_canonical.py::TestRsi",
                 "parity": "tests/features/test_parity.py"},
    "approval": {"scope": ["benchmark", "research"], "production": false}
  },
  "availability": {
    "vectorta": {"batch": {"state": "native", "variant": "canonical"},
                 "stream": {"state": "native", "variant": "canonical"}},
    "nautilus": {"native": {"state": "variant", "variant": "nt_init_period_minus_1_scaled_0_1",
                 "note": "Seeds at period−1 (canonical: period) and works internally in 0..1; the provider rescales it to 0..100."}}
  }
}

Qué te dice la ficha, en castellano:

  • Fórmula: RSI de Wilder; plano = 50, solo ganancias = 100, solo pérdidas = 0.
  • Contrato: entra close, sale rsi, válido desde period (14 con el ejemplo).
  • Evidencia: el test de fidelidad y el de paridad que respaldan la afirmación.
  • Por motor: VectorTA reproduce la canónica en batch y stream; Nautilus es una variante (arranca en period − 1 y trabaja en 0..1).

Y como está registrada, se puede calcular por la API común:

curl -sS -X POST "$BASE/v1/indicators" -H 'Content-Type: application/json' \
  -d @examples/api/05_indicators_rsi14_nvda.request.json | jq '.payload.status'
# "PASS" — con engine "both", compara VectorTA y Nautilus y devuelve la paridad

En la respuesta real (05_indicators_rsi14_nvda.response.json) VectorTA declara first_valid_index: 14, n_bars_in: 631735, n_valid: 631721 y leading_nan: 14 sobre NVDA 1min, con el data_hash e8b5fc36… en la firma.

4.2 alma: un indicador solo de motor

Extracto de examples/api/14_help_engine_only_alma.response.json:

{
  "id": "alma",
  "kind": "engine_indicator",
  "project": {"registered": false, "primitive": null, "phase": null},
  "capability": {"level": "discovered", "computable_via_api": true,
                 "execution_mode": "engine_passthrough", "computable_engines": ["vectorta"],
                 "guarantees": {"canonical_formula": false, "first_valid_rule": "observed",
                                "parity": "not_applicable"}},
  "engines": {"vectorta": true, "nautilus": false},
  "engines_detail": {"vectorta": {
      "function": "alma", "batch_function": "alma_batch", "stream_class": "AlmaStream",
      "signature": "(data, period, offset, sigma, kernel=None)"}}
}

alma existe en VectorTA pero no tiene contrato del proyecto: ni formula_version, ni first_valid declarado, ni tests. Aun así, POST /v1/indicators lo calcula por paso directo al motor (execution_mode: engine_passthrough): devuelve los valores de VectorTA con el first_valid observado y sin paridad (ejemplo real en examples/api/17_indicators_alma_passthrough.*, explicado en Indicadores por API). También puedes usarlo directamente con su motor:

import vector_ta as va
out = va.alma(close, period=9, offset=0.85, sigma=6.0)       # batch
stream = va.AlmaStream(period=9, offset=0.85, sigma=6.0)     # incremental
valor = stream.update(close_t)

¿Y si quiero alma con garantías canónicas?

El paso directo no lo promueve. Hay que promoverlo: fórmula canónica, parámetros, first_valid, warmup, test de fidelidad, paridad por carril y registro de aprobación. Es el checklist del capítulo siguiente.


5. La tabla docs/INDICATORS.md

Generada por tools/list_indicators.py; una fila por indicador canónico.

Columna Significado
VectorTA batch / VectorTA stream el motor expone función completa / clase incremental
Nautilus native / Nautilus stream el motor expone clase de indicador / update_raw/update_bar
Registered true para las 39 primitivas
Phase A, B o C para las registradas; - para el resto
Params nombres de parámetros de ejemplo
Level discovered, implemented, verified o approved

Muestra real:

Indicator VectorTA batch VectorTA stream Nautilus native Nautilus stream Registered Phase Params Level
rsi true true true true true A period approved
tr false false false false true A approved
macd true true true true true B fast,slow,signal approved
session_vwap false false false false true B approved
alma true true false false false - discovered

Observa tr: ningún motor lo expone como función suelta y, sin embargo, es una primitiva aprobada. Es un cálculo propio (custom_reference) con su test. Registrado no significa «nativo de un motor».

docker compose --profile dev run --rm -T dev python tools/list_indicators.py \
    --format md --output docs/INDICATORS.md      # también --format csv

Resumen

  • El catálogo es la unión introspectada de VectorTA 0.2.8, NautilusTrader 1.231.0 y el registro del proyecto: 386 entradas (346 VectorTA, 36 Nautilus, 15 en ambos).
  • 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.
  • Las 39 primitivas registradas tienen contrato; las 347 solo de motor siguen en discovered aunque se calculen por paso directo.
  • GET /v1/indicators filtra por engine, registered, verified, approved y q; GET /v1/help indexa 417 temas.
  • Una ficha registrada trae fórmula, contrato, evidencia y disponibilidad por motor; una solo de motor trae la firma nativa y cómo llamarla.

Para practicar

  1. Con la API levantada, cuenta cuántas entradas devuelve engine=nautilus&registered=false. ¿Cuadra con 36 − (registradas con carril Nautilus)?
  2. Busca con q=vwap y explica por qué session_vwap es approved pero vwap es discovered.
  3. Pide GET /v1/help/macd y anota qué variante declara cada motor.
  4. Intenta calcular alma con POST /v1/indicators y copia el código de error. ¿Qué dos formas hay de obtener el número?