Saltar a contenido

Niveles de capacidad: descubierto, implementado, verificado, aprobado

Un catálogo que mezcla «el motor lo tiene», «el proyecto lo calcula», «hay tests que lo prueban» y «alguien lo ha aprobado para un uso» es un catálogo que miente sin querer. El banco de pruebas separa esas cuatro afirmaciones en una escalera de niveles y obliga a que cada indicador declare exactamente uno: el más alto que ha alcanzado.

Qué vas a aprender

  • Los cuatro niveles: discovered → implemented → verified → approved.
  • Qué evidencia exige cada peldaño y dónde vive en el código.
  • El checklist de promoción de un indicador.
  • Por qué no hay auto-promoción y qué significa production: false.
  • Dónde aparecen los niveles (API, tabla, fichas de ayuda).

1. La escalera

flowchart LR
    D["discovered<br/>el motor lo expone<br/>347"] -->|contrato del proyecto| I["implemented<br/>primitiva registrada<br/>39"]
    I -->|tests de fidelidad<br/>+ paridad por carril| V["verified<br/>evidencia automática<br/>39"]
    V -->|registro de aprobación<br/>con alcance| A["approved<br/>benchmark + research<br/>39"]
Nivel Afirmación ¿Contrato del proyecto? ¿POST /v1/indicators? Evidencia
discovered Un motor instalado lo expone en al menos un carril No Solo por paso directo al motor (342 de 347), sin garantías el comportamiento del propio motor
implemented Es una primitiva registrada: fórmula canónica, parámetros, warmup, clave de caché, rol Sí, canónico (33 de 39; las otras 6 leen series derivadas o paneles) tests de registro/contrato
verified Implementada y su fidelidad y la paridad de sus carriles están probadas verified_test_id + streaming_verified_test_id
approved Verificada y un registro declarado le concede un alcance finazbench/features/approval.py

La escalera es monótona: approved implica verified, que implica implemented. Una entrada que solo es discovered nunca se presenta como ninguna de las otras tres.

Analogía: el carné de conducir

discovered es saber que existe el coche. implemented, haber estudiado el código de circulación (hay reglas escritas). verified, haber aprobado el examen práctico (hay evidencia). approved, tener el carné para una categoría concreta: aquí, «benchmark» e «investigación», nunca «producción».


2. Cada peldaño con detalle

2.1 discovered (347 entradas)

finazbench/features/catalog.py recorre los wheels instalados (_vectorta_records, _nautilus_records): una función batch o una clase *Stream en VectorTA; una subclase concreta de Indicator en Nautilus. La sonda ejecuta 100 puntos antes de declarar un carril disponible.

Un indicador descubierto no tiene contrato: ni formula_version, ni parámetros canónicos, ni first_valid, ni warmup, ni clave de caché. «Descubierto» no significa roto ni de segunda: significa que se usa con la semántica de su motor.

El paso directo al motor NO promueve el nivel

Desde el paquete de la API de 2026-09-22, POST /v1/indicators calcula 342 de estas 347 entradas por paso directo al motor (execution_mode: engine_passthrough). La respuesta lo declara: capability.level sigue siendo discovered, guarantees.canonical_formula es false, first_valid_rule es observed y no hay paridad. Poder calcular un indicador no es tener un contrato: la única vía para subir de nivel es el checklist de promoción de este capítulo. Las 5 entradas no ejecutables (rsmk, spearman_correlation, decisionpoint_breadth_swenlin_trading_oscillator, SpreadAnalyzer, half_causal_estimator) explican su motivo en capability.not_computable_reason.

2.2 implemented (39)

La primitiva se registra en finazbench/features/ con:

  • fórmula con formula_version (registry.build_spec es el único constructor legítimo);
  • parámetros canónicos, validados y de orden estable;
  • inputs/outputs y regla de first_valid (por salida si difieren);
  • warmup (warmup.required_history) con reglas de cadena y paralelismo;
  • clave de caché determinista (FeatureSpec.cache_key_parts);
  • rol en el catálogo de estrategias.

Las 39 se registran en tres fases: 11 de fase A, 23 de fase B y 5 de fase C. De ellas, 33 son ejecutables por POST /v1/indicators; las otras 6 (bandwidth, rolling_quantile, linreg_endpoint, sma_of, session_position, cross_sectional_rank) leen series derivadas o paneles y solo se usan dentro de estrategias (422 con not_computable_reason).

2.3 verified (39)

Dos pruebas independientes:

  1. Fidelidad del kernel canónico a la fórmula (ventanas, semillas, first_valid, NaN, bordes): tests/features/test_canonical.py (fase A), la suite test_ext_* (fases B/C) y tests/features/test_streaming_ext.py.
  2. Paridad de cada carril declarado: batch y stream de cada motor contra la canónica desde el first_valid común, con la tolerancia registrada (y los streams de Nautilus contra su propio batch, exactos). Evidencia: tests/features/test_parity.py y test_streaming_ext.py::TestParidadStreamBatch.

2.4 approved (39)

Una entrada explícita y revisable en finazbench/features/approval.py con su alcance:

Alcance Valor
benchmark true: se puede usar en campañas y resultados publicados
research true: barridos, estudios, derivaciones
production false

production: false no es una tarea pendiente

Este repositorio es un banco de pruebas para comparar motores y medir paridad. Ningún indicador ni ninguna estrategia se declara aprobada para operar con dinero real, ni aquí ni en el registro. Un resultado approved es válido para benchmark e investigación, y para nada más.


3. Checklist de promoción

Para llevar un indicador de discovered a approved (cambio manual y revisable):

# Paso Qué se entrega
1 Fórmula canónica Definición exacta: semillas, ventana inclusiva o no, escala, política de NaN. Si el motor difiere, se dice.
2 Parámetros Nombres, tipos, límites y defaults; cuáles afectan al número (entran en la clave de caché).
3 first_valid Regla por salida; first_valid_by_output si las salidas calientan distinto.
4 Warmup warmup.required_history con dependencias paralelas y encadenadas (R1–R3). Un warmup mal declarado convierte NaN en señales falsas.
5 Test de fidelidad Valores calculados a mano o fixture congelado; debe fallar si cambia la fórmula.
6 Carriles de paridad Proveedores soportados, tolerancias con motivo, test stream/batch por carril. Un carril que calcula otra variante queda variant/unsupported con nota.
7 Registro de aprobación Solo con 1–6 en verde: entrada en approval.py con su alcance (por defecto benchmark + research).
flowchart TD
    S[indicador descubierto] --> F{¿fórmula canónica<br/>decidida y escrita?}
    F -- no --> S
    F -- sí --> T{¿test de fidelidad<br/>y paridad en verde?}
    T -- no --> I[implemented<br/>no verificado]
    T -- sí --> R{¿registro de aprobación<br/>revisado?}
    R -- no --> V[verified]
    R -- sí --> A[approved<br/>benchmark + research]

4. Por qué no hay auto-promoción

La introspección puede probar que un nombre existe y corre. No puede probar:

  • cuál es la fórmula canónica;
  • cómo siembra el motor;
  • por qué diverge de un indicador hermano del otro motor.

Esas son decisiones que exigen leer el motor y escribir un test. Por eso quedan registradas como un diff revisado, no como efecto secundario de actualizar un wheel.

Un caso real: supertrend de VectorTA

vector_ta.supertrend existe y corre. Pero su segunda salida es una bandera {0, 1} que coincide con la dirección canónica en solo 2.229 de 4.991 barras (44,7 %, menos que una moneda). Si el catálogo se hubiera auto-promovido, supertrend habría quedado «verificado» con la fórmula equivocada. El proyecto sirve en su lugar la recursión canónica sobre el ATR nativo de VectorTA (custom_reference_on_vta_atr), que sí reproduce la dirección en 4.991 de 4.991.

La segunda regla es simétrica: no se degrada evidencia en silencio. Un carril unsupported o variant se publica con su motivo; si falta el test id, la afirmación no se hace; si lo declarado y lo observado difieren, se guardan ambos en runs/env/capabilities.json.


5. Dónde se ven los niveles

Lugar Qué muestra
GET /v1/indicators capability en cada entrada y capability_counts en el payload; filtros verified y approved
docs/INDICATORS.md columna Level por fila
GET /v1/help/{name} bloque capability con level, computable_via_api, evidence y approval
runs/env/capabilities.json matriz de capacidad (102 filas, fases A/B × 3 proveedores): «¿el carril existe y corre?»
runs/parity/summary.json paridad de estrategias: «¿se reproducen los trades entre motores?»

Capacidad no es paridad, y ninguna es aprobación

capabilities.json responde si un carril existe y corre; summary.json, si una estrategia reproduce trades equivalentes. Ninguno de los dos es una aprobación: la aprobación es el registro declarado.

6. Lo que los niveles NO significan

  • discovered no significa roto ni no soportado: se usa con su motor.
  • implemented no significa verificado; verified no significa rentable ni mejor.
  • approved no significa aprobado para producción.
  • Ningún nivel implica que una estrategia que use el indicador esté aprobada, ni validación contra el mercado: la paridad es equivalencia entre motores de la fórmula canónica, no una afirmación sobre retornos.

Resumen

  • Cuatro niveles monótonos: discovered (347), implemented (39), verified (39), approved (39).
  • 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; el paso directo no promueve el nivel.
  • Cada peldaño añade una evidencia concreta: contrato, tests de fidelidad y paridad, registro de aprobación.
  • La promoción es un cambio manual revisado con siete pasos; no hay auto-promoción.
  • El alcance de la aprobación es benchmark + research; production: false siempre.

Para practicar

  1. Elige un indicador discovered de docs/INDICATORS.md y redacta los pasos 1–3 del checklist para él (fórmula, parámetros, first_valid).
  2. ¿Qué pasaría si un indicador se promoviera con el warmup mal declarado? Pon un ejemplo con una EMA.
  3. Explica por qué tr es approved aunque ningún motor lo exponga.
  4. Pide GET /v1/indicators?verified=true y ?approved=true: ¿por qué hoy devuelven el mismo número?