Catálogo y ayuda¶
Qué vas a aprender¶
- La diferencia entre plantilla (receta del catálogo) e instancia (plantilla + parámetros concretos).
- Cómo listar las 31 plantillas de estrategia con
GET /v1/catalog/strategiesy ver la ficha de una. - Cómo explorar el catálogo completo de indicadores (386 entradas) con
GET /v1/indicatorsy sus filtros. - Qué significan los niveles de capacidad
discovered → implemented → verified → approved, y por qué la API calcula 375 indicadores pero solo 33 con garantías canónicas. - Cómo pedir la ficha de un indicador con
GET /v1/indicators/{name}, incluidos nombres nativos de cada motor. - Cómo usar la superficie de ayuda (
GET /v1/helpyGET /v1/help/{name}) como manual de bolsillo.
Todas las rutas de este capítulo son GET de solo lectura: no ejecutan nada ni escriben en disco. Son la «carta del restaurante» antes de pedir.
1. El mapa: tres catálogos, una ayuda¶
flowchart TB
subgraph Estrategias
CS["GET /v1/catalog/strategies<br/>31 plantillas P01..P20, Q01..Q10"] --> CT["GET /v1/catalog/strategies/{template_id}<br/>ficha completa"]
end
subgraph Indicadores
I["GET /v1/indicators<br/>386 entradas (filtros)"] --> ID["GET /v1/indicators/{name}<br/>ficha de uno"]
end
subgraph Ayuda
H["GET /v1/help<br/>417 temas"] --> HN["GET /v1/help/{name}<br/>dossier de uso"]
end
CT -. mismo id .-> HN
ID -. mismo nombre .-> HN
| Pregunta que te haces | Ruta |
|---|---|
| ¿Qué estrategias hay? | GET /v1/catalog/strategies |
| ¿Qué parámetros acepta P01 y qué restricciones tiene? | GET /v1/catalog/strategies/P01 o GET /v1/help/P01 |
| ¿Qué indicadores existen en VectorTA y en Nautilus? | GET /v1/indicators?engine=… |
| ¿Puedo calcular este indicador por la API? | GET /v1/indicators/{name} → capability.computable_via_api |
| ¿Cómo lo llamo en Python o con curl? | GET /v1/help/{name} → examples, example_curl |
2. Plantillas de estrategia¶
2.1 Plantilla frente a instancia¶
Una plantilla es como una receta de cocina («tortilla de patatas: huevos, patatas, cebolla opcional»). Una instancia es la tortilla concreta que haces hoy («6 huevos, 500 g de patata, con cebolla») y a la que das nombre.
| Nivel | Qué es | Quién la define | Ejemplo |
|---|---|---|---|
| Plantilla | Una de las 31 recetas del catálogo: regla canónica, defaults, parameter_grid, esquema de params, features, formula_version |
El proyecto (catalog/strategy_catalog.json) |
P01 «Cruce de medias EMA» |
| Instancia | Plantilla + params + nombre + id determinista | Tú | P01-dc9260 «EMA cross 20/50 base» |
GET /v1/catalog/strategies lista plantillas, no instancias. Para instancias está GET /v1/strategies (lo verás en el capítulo 3). El detalle de cada plantilla está explicado en la Parte V.
2.2 GET /v1/catalog/strategies¶
Filtros de consulta (según finazbench/api/routers/catalog.py):
| Parámetro | Valores | Nota |
|---|---|---|
category |
popular | quant |
Populares P01–P20; cuantitativas Q01–Q10. |
milestone |
H1..H5 |
Hito del plan en que entra la plantilla. |
status |
p. ej. implemented |
Estado de implementación. |
supported_by |
adaptador | Hoy responde 501 ENDPOINT_NOT_IMPLEMENTED (el código 37 del servidor, fuera de los 36 del contrato; ver capítulo 1): filtrar por adaptador exigiría la matriz real probada, y el servidor prefiere negarse a devolver una lista basada en una conjetura. |
Extracto de la forma de la respuesta según el contrato (docs/API.md §6.2):
{
"payload": {
"catalog_version": "1.0.0",
"count": 31,
"templates": [
{ "template_id": "P01", "name": "Cruce de medias EMA", "category": "popular",
"formula_version": "1.0.0", "milestone": "H1", "status": "implemented",
"features": ["ema_fast", "ema_slow"], "defaults": { "fast": 20, "slow": 50 },
"grid_size": 16, "valid_grid_size": 16, "data_requirements": ["OHLC"],
"expected_algorithmic_cost": "O(N)" },
"…"
]
}
}
grid_size frente a valid_grid_size
grid_size es el producto cartesiano de la rejilla; valid_grid_size descuenta las combinaciones que violan restricciones. En P01 (fast ∈ {5,10,20,40}, slow ∈ {50,100,150,200}) coinciden: 16 y 16, porque el mayor fast (40) es menor que el menor slow (50). En P11, de 15 parejas, entry=20, exit=20 viola exit < entry, así que valid_grid_size es 14.
¿Por qué Q08 y Q08B son dos plantillas?
El catálogo original tiene un único Q08 con model como parámetro. La API lo publica partido: Q08 (Ridge, siempre disponible) y Q08B (CatBoost, dependencia opcional). El soporte es una propiedad de la plantilla, no de un parámetro: si fuera un parámetro, /v1/capabilities no podría declarar UNSUPPORTED para una parte del espacio de parámetros.
2.3 GET /v1/catalog/strategies/{template_id}¶
La ficha completa: regla canónica, param_schema (JSON Schema), constraints, parameter_grid, y sobre todo features_detail con depends_on_params, que es lo que permite a la API saber qué se reutiliza al cambiar un parámetro.
curl -sS "$BASE/v1/catalog/strategies/P01" \
| jq '.payload | {canonical_rule, constraints, features_detail: [.features_detail[] | {name, depends_on_params}]}'
Forma según el contrato:
{
"canonical_rule": "Con ambas medias válidas, objetivo +1 si EMA(f)>EMA(s), -1 si EMA(f)<EMA(s); igualdad conserva el objetivo anterior. …",
"constraints": [
{ "rule": "fast < slow", "message": "slow debe ser estrictamente mayor que fast.", "fields": ["fast", "slow"] }
],
"features_detail": [
{ "name": "ema_fast", "depends_on_params": ["fast"] },
{ "name": "ema_slow", "depends_on_params": ["slow"] }
]
}
Una plantilla inexistente devuelve 404 TEMPLATE_NOT_FOUND.
Lectura de trader
Si ema_slow depende solo de slow, subir slow de 50 a 100 no obliga a recalcular la EMA rápida. Es la base del ahorro en barridos y derivaciones.
3. El catálogo completo de indicadores¶
3.1 386 descubiertos no son 386 calculables¶
GET /v1/indicators enumera todo lo que exponen los motores instalados, fusionado con las primitivas registradas del proyecto. Los números del ejemplo real examples/api/08_indicators_catalog.response.json:
| Medida | Valor |
|---|---|
Tamaño del catálogo (catalog_size) |
386 |
| Con carril VectorTA | 346 |
| Con carril Nautilus | 36 |
En los dos motores (both_engines) |
15 |
| Primitivas registradas del proyecto | 39 |
Calculables por POST /v1/indicators (computable_via_api) |
375 |
…con fórmula canónica y paridad verificada (execution_mode: canonical) |
33 |
…por paso directo al motor, sin garantías (capability_counts.computable_passthrough) |
342 |
No ejecutables, con not_computable_reason |
11 |
¿Por qué solo 33 con garantías? Porque «existir en una librería» (o poder calcularse por paso directo) no es lo mismo que «tener un contrato». Cada entrada publica su nivel de capacidad, una escalera monótona:
stateDiagram-v2
direction LR
[*] --> discovered: lo expone un motor
discovered --> implemented: fórmula canónica, params,<br/>first_valid, warmup, clave de caché
implemented --> verified: test de fidelidad<br/>+ test de paridad entre carriles
verified --> approved: registro de aprobación<br/>scope benchmark/research
| Nivel | Significado | ¿Calculable por la API? |
|---|---|---|
discovered |
Un motor lo expone, pero el proyecto no tiene contrato. Lleva promotion_note. |
Solo por paso directo al motor (342 de 347), sin garantías; el nivel no sube |
implemented |
Primitiva registrada con fórmula canónica, params, first_valid, warmup y rol de caché. |
Sí, canónico (33 de 39) |
verified |
+ evidencia automatizada (tests de fidelidad y paridad) en capability.evidence. |
Sí |
approved |
+ registro en finazbench.features.approval, alcance benchmark y research, production: false. |
Sí |
Del ejemplo real: capability_counts = {"discovered": 347, "implemented": 39, "verified": 39, "approved": 39, "computable_passthrough": 342} y computable_via_api = 375. Los niveles son acumulativos, así que discovered + implemented = 347 + 39 = 386 = catalog_size; computable_passthrough no es un nivel, solo cuenta las entradas discovered que el paso directo sabe calcular.
production: false siempre
Este repositorio es un banco de pruebas. Ninguna aprobación es para producción, y la API lo declara en cada ficha. No leas approved como «apto para operar con dinero real».
3.2 Filtros de GET /v1/indicators¶
| Parámetro | Valores | Defecto | Efecto |
|---|---|---|---|
engine |
all | vectorta | nautilus |
all |
Solo entradas con carril en ese motor. |
registered |
all | true | false |
all |
true = las 39 primitivas; false = solo de motor. |
verified |
all | true | false |
all |
true = verified y approved. |
approved |
all | true | false |
all |
true = las del registro de aprobación (39). |
mode |
all | canonical | passthrough |
all |
canonical = las 39 primitivas; passthrough = las 347 discovered (342 ejecutables por paso directo). |
view |
summary | full |
summary |
full añade módulo/función/clase de las entradas de motor, passthrough_params y, si es calculable, example_request y example_curl. |
q |
subcadena (≤200) | — | Búsqueda sin mayúsculas en nombre y descripción. |
limit / offset |
1..2000 / ≥0 | 500 / 0 | Paginación. |
Tres campos de conteo que conviene no confundir:
count: entradas en esta respuesta.total: entradas que pasan los filtros, antes delimit/offset.catalog_size: tamaño sin filtrar (386).
Resultados reales de los ejemplos regenerados:
| Petición | Fichero | count |
total |
|---|---|---|---|
GET /v1/indicators |
08_indicators_catalog.response.json |
386 | 386 |
GET /v1/indicators?engine=nautilus&limit=40 |
11_indicators_catalog_nautilus.response.json |
36 | 36 |
GET /v1/indicators?approved=true |
16_indicators_catalog_approved.response.json |
39 | 39 |
# Tamaño e inventario
curl -sS "$BASE/v1/indicators" | jq '.payload | {count, total, catalog_size, capability_counts, computable_via_api}'
# Los 36 nativos de Nautilus
curl -sS "$BASE/v1/indicators?engine=nautilus" | jq '.payload.total'
# Las 39 primitivas aprobadas
curl -sS "$BASE/v1/indicators?approved=true" | jq -r '.payload.indicators[].name'
# Buscar por texto
curl -sS "$BASE/v1/indicators?q=bollinger" | jq -r '.payload.indicators[] | [.name, .both_engines] | @tsv'
# Paginar las de solo-motor
curl -sS "$BASE/v1/indicators?registered=false&limit=10&offset=10" | jq -r '.payload.indicators[].name'
import requests
BASE = "http://localhost:8000"
def pages(**filters):
offset = 0
while True:
p = requests.get(f"{BASE}/v1/indicators",
params={**filters, "limit": 100, "offset": offset}).json()["payload"]
yield from p["indicators"]
offset += p["count"]
if offset >= p["total"] or p["count"] == 0:
break
both = [i["name"] for i in pages() if i.get("both_engines")]
print(len(both), both)
3.3 Cómo es una entrada¶
Una primitiva registrada (extracto real de 08, entrada sma):
{
"name": "sma",
"engines": { "vectorta": { "batch": true, "stream": true },
"nautilus": { "native": true, "stream": true } },
"project": { "registered": true, "primitive": "sma", "phase": "A" },
"capability": { "level": "approved", "computable_via_api": true,
"approval": { "scope": ["benchmark", "research"], "production": false, "…": "…" },
"…": "…" },
"first_valid_rule": "period_minus_1",
"params": [ { "name": "period", "type": "int", "required": true, "example": 10 } ],
"…": "…"
}
Una entrada solo de motor (extracto real de 08):
{
"name": "absolute_strength_index_oscillator",
"engines": { "vectorta": { "batch": true, "stream": true },
"nautilus": { "native": false, "stream": false } },
"project": { "registered": false, "primitive": null, "phase": null },
"capability": { "level": "discovered", "…": "…" },
"both_engines": false
}
Los 15 indicadores presentes en ambos motores en el ejemplo 08 son: sma, ema, rma, rsi, bbands, atr, donchian, wma, hma, macd, keltner_sma, stochrsi, dmi, psychological_line y vertical_horizontal_filter.
El bloque engines del payload
Además de la lista, la respuesta trae payload.engines, un resumen por motor. Del ejemplo real: VectorTA 0.2.8, kernel scalar, catalog: {indicators: 346, batch: 342, stream: 334}; Nautilus 1.231.0, catalog: {indicators: 36, native: 36, stream: 35}. Los contadores batch/stream/native (p. ej. native: 8, custom_reference: 31 en el batch de VectorTA) se refieren solo a las 39 primitivas registradas: cuántas se sirven con la función nativa del motor y cuántas con una implementación de referencia propia.
4. La ficha de un indicador: GET /v1/indicators/{name}¶
Acepta tres formas de nombre:
- el nombre de la primitiva del proyecto (
rsi,bbands,keltner_sma); - el nombre nativo de cualquiera de los motores (
BollingerBands,AroonOscillator,wilders); - variantes de estilo (
aroon_oscillator,bollingerbands).
curl -sS "$BASE/v1/indicators/rsi" | jq '.payload.indicator | {name, first_valid_rule, both_engines}'
curl -sS "$BASE/v1/indicators/wilders" | jq -r '.payload.indicator.name' # -> rma
curl -sS -o /dev/null -w '%{http_code}\n' "$BASE/v1/indicators/not_an_indicator" # 404
Lo más valioso de la ficha es la disponibilidad por motor, que declara las variantes en lugar de esconderlas. Extracto real de 09_indicator_detail.response.json (RSI):
{
"vectorta": {
"batch": { "state": "native", "variant": "canonical", "note": null },
"stream": { "state": "native", "variant": "canonical", "note": null }
},
"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." },
"stream": { "state": "variant", "variant": "nt_init_period_minus_1_scaled_0_1", "note": "…" }
}
}
Ejemplo de trading: el RSI no arranca igual en los dos motores
El RSI de Nautilus «siembra» una barra antes (period−1) que el canónico (period) y trabaja internamente en 0..1. Por eso, al calcular el RSI14 sobre NVDA 1min, el primer valor válido es el índice 14 en VectorTA y 13 en Nautilus (lo veremos en el capítulo 5). No es un fallo: es una variante declarada.
Cada ficha registrada incluye también example_request y example_curl listos para copiar. El real de 09:
curl -sS -X POST "$BASE/v1/indicators" -H 'Content-Type: application/json' -d '{"schema_version": "v1", "payload": {"data": {"asset_id": "NVDA", "timeframe": "1d", "window": {"start": null, "end": null, "mode": "reset_flat"}}, "indicator": {"indicator": "rsi", "params": {"period": 14}, "source": "close"}, "engine": "both", "engine_options": {"vectorta": {"kernel": "scalar", "use_batch": true}, "nautilus": {"adapter": "NT_FEATURES", "indicator_provider": "native"}}}}'
Una ficha solo de motor (p. ej. alma) lleva registered: false, la nota de que no es calculable por POST /v1/indicators y engines_detail con módulo y firma. Del ejemplo real 14: módulo vector_ta, función alma, batch alma_batch, clase stream AlmaStream, firma (data, period, offset, sigma, kernel=None).
5. La ayuda: GET /v1/help y GET /v1/help/{name}¶
5.1 El índice¶
La ayuda organiza 417 temas en tres familias:
Familia (kind) |
Qué contiene | Nº |
|---|---|---|
indicator |
Primitivas registradas | 39 |
engine_indicator |
Indicadores solo de motor (342 calculables por paso directo, sin garantías) | 347 |
strategy |
Plantillas P01..P20, Q01..Q10 | 31 |
Filtros: kind (all, indicator, engine_indicator, strategy), q (subcadena en id y resumen) y limit (1..2000, defecto 500).
Respuesta real de GET /v1/help?limit=20 (12_help_index.response.json), recortada:
{
"payload": {
"count": 20, "total": 417,
"filters": { "kind": "all", "q": null, "limit": 20 },
"topics": [
{ "id": "sma", "kind": "indicator", "summary": "Simple moving average of `period` consecutive valid observations." },
{ "id": "ema", "kind": "indicator", "summary": "Exponential moving average; seed = SMA of the first `period` valid values, alpha = 2/(n+1)." },
{ "id": "rma", "kind": "indicator", "summary": "Wilder's moving average; seed = SMA of the first `period` valid values, alpha = 1/n." },
"…"
]
}
}
Idioma
Los temas de indicador están en inglés; los resúmenes y descripciones de estrategia conservan la redacción original (en español) del catálogo.
5.2 El dossier de un tema¶
La forma depende de la familia. Las claves reales de cada dossier de ejemplo:
| Ejemplo | kind |
Campos principales |
|---|---|---|
13_help_indicator_rsi |
indicator |
params, inputs/outputs, first_valid_rule, availability, capability, examples (batch/stream/nautilus), example_curl, feature_roles |
14_help_engine_only_alma |
engine_indicator |
engines, engines_detail, examples, capability (discovered + promotion_note), note |
15_help_strategy_p01 |
strategy |
params, defaults, parameter_grid, constraints, features, policy_params, warmup_rule, example_curl |
Los ejemplos reales de código del dossier 13:
# batch (VectorTA)
import vector_ta as va
out = va.rsi(close, period=14) # runnable with the example parameters
# stream (VectorTA)
stream = va.RsiStream(period=14)
result = stream.update(close_t)
# nautilus
from nautilus_trader.indicators import RelativeStrengthIndex
indicator = RelativeStrengthIndex(...) # fill the required parameters marked with `...`
indicator.update_raw(close)
Y feature_roles dice qué estrategias lo usan: P02 (depende de period), P17 (de rsi_period), Q08 y Q08B.
Respuesta real (dossier 15, recortada):
{
"kind": "strategy",
"name": "Cruce de medias EMA",
"defaults": { "fast": 20, "slow": 50 },
"parameter_grid": { "fast": [5, 10, 20, 40], "slow": [50, 100, 150, 200] },
"constraints": [ { "rule": "fast < slow", "message": "slow debe ser estrictamente mayor que fast.", "fields": ["fast", "slow"] } ],
"warmup_rule": "max(first_valid_index de las features implicadas) bajo el proveedor efectivo; se documenta por corrida."
}
Su example_curl es un POST /v1/backtest completo con plantilla en línea (template_id + params), NVDA 1d y cost_scenario: "zero".
{
"kind": "engine_indicator",
"engines": { "vectorta": true, "nautilus": false },
"note": "This indicator is not registered as a project primitive; not computable via POST /v1/indicators."
}
Su capability.promotion_note explica qué haría falta para promocionarlo: fórmula canónica, params, first_valid, warmup, test de fidelidad, paridad entre carriles y alta en el registro de aprobación (docs/CAPABILITY_LEVELS.md).
Un tema desconocido nunca es un 200 vacío: devuelve 404 HELP_TOPIC_NOT_FOUND.
6. Flujo recomendado antes de pedir un cálculo¶
sequenceDiagram
participant T as Trader
participant API as bench-api
T->>API: GET /v1/help?kind=strategy&q=RSI
API-->>T: P02, P17, …
T->>API: GET /v1/help/P02
API-->>T: defaults, grid, constraints, example_curl
T->>API: GET /v1/indicators/rsi
API-->>T: first_valid_rule, availability (variante en Nautilus)
T->>API: POST /v1/backtest (capítulo 3)
Resumen¶
- Las plantillas (31) son recetas inmutables; las instancias son plantilla + params con id determinista.
GET /v1/catalog/strategiesfiltra porcategory,milestoneystatus;supported_byresponde hoy501por honestidad.GET /v1/indicatorsenumera 386 entradas: 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. Solo las que tienen contrato (implemented/verified/approved) dan garantías.count≠total≠catalog_size; pagina conlimit/offset.- La ficha
GET /v1/indicators/{name}resuelve nombres nativos y declara las variantes por motor. GET /v1/help(417 temas) yGET /v1/help/{name}dan ejemplos de Python y unexample_curllisto para copiar.
Para practicar¶
- ¿Cuántas plantillas
quanthay en el hitoH4? Usacategoryymilestone. - Lista los indicadores con carril en los dos motores y comprueba que son 15.
- Pide
GET /v1/indicators/BollingerBands. ¿A qué primitiva canónica resuelve? - Elige un indicador
discoverede intenta calcularlo conPOST /v1/indicators. ¿Qué error recibes y qué dice supromotion_note? - Usando
GET /v1/help/P02, identifica qué parámetros son de política y cuáles de feature. ¿Qué implica para una derivación que cambie los umbrales 30/70 → 25/75?