- Python 90.7%
- PLpgSQL 7.4%
- CSS 0.6%
- JavaScript 0.5%
- HTML 0.4%
- Other 0.3%
| .forgejo/workflows | ||
| config | ||
| datasets | ||
| docs | ||
| infra | ||
| src/atlas_system | ||
| stubs/ibapi | ||
| tests | ||
| .dockerignore | ||
| .editorconfig | ||
| .env.example | ||
| .gitignore | ||
| AGENTS.md | ||
| compose.ibkr-paper-host.yaml | ||
| compose.ibkr-paper.yaml | ||
| compose.integration.yaml | ||
| compose.yaml | ||
| Dockerfile | ||
| Makefile | ||
| pyproject.toml | ||
| README.md | ||
ATLAS
ATLAS es un sistema autónomo de inversión sistemática, multi-estrategia y multi-activo. Su diseño pone el control de riesgo, la trazabilidad y la paridad entre backtest, paper trading y producción por delante de cualquier señal de inversión.
Este repositorio contiene la fase 0 — Cimientos, la implementación funcional de la fase 1 — Algoritmo y los trece primeros incrementos de la fase 2 — Operativa:
- contratos de dominio y eventos inmutables;
- M1: pipeline de ingesta con validación fail-safe;
- M2: esquema inicial para TimescaleDB, Redis Streams y almacenamiento de objetos S3 local con SeaweedFS;
- M10: backtesting orientado a eventos, evidencia segmentada y registro de ensayos append-only con congelación de candidato y holdout único;
- API mínima con salud, disponibilidad, métricas e ingesta;
- backfill histórico de acciones/ETFs mediante Massive y cripto mediante Kraken, archivando la respuesta original en S3 antes de normalizarla;
- calendario XNYS con festivos y cierres anticipados, detección/reparación idempotente de huecos y registro inmutable de splits/dividendos;
- entorno reproducible con Docker Compose y CI para Forgejo.
- indicadores y detector de régimen deterministas;
- construcción automática de características desde barras normalizadas de M2;
- S1 momentum relativo con ranking, pesos inversos a ATR, trailing stop y explicaciones auditables.
- S2 Donchian con modo defensivo, S3 reversión de corto plazo y S4 tendencia cripto, todos solo largos, con stops obligatorios y salidas deterministas.
- M4 con ensemble adaptativo acotado, gating por régimen, sizing por riesgo, volatilidad y ¼-Kelly, bandas y límites de concentración.
- M5 como proceso HTTP independiente y fail-safe, con drawdowns, cooldown, recuperación gradual, circuit breakers, HALT y kill switch.
- validador obligatorio esquema 2.1 para roles
development_core,regime_warmupyfrozen_holdout, fronteras de proveedor, walk-forward 3+1, elegibilidad explícita de artefactos, métricas OOS separadas, perturbaciones ±20% y Monte Carlo determinista de 1.000 remuestreos. - núcleo M6 broker-neutral con planificación sell-first, límites ±0,2%, TWAP, stops obligatorios y simulador determinista e idempotente sin acceso a red.
- journal M6 append-only en PostgreSQL: reserva previa del plan, persistencia atómica de resultados/fills/stops/reconciliaciones y replay durable de informes terminados tras reinicio.
- proceso M6 independiente con comando causal M4→M5→M6, heartbeat auditable, readiness sobre sus dependencias y latch fail-closed que comunica incidentes a HALT en M5.
- scheduler M6 durable: acciones en la siguiente apertura XNYS, cripto
inmediata, separación TWAP real, dispatch append-only antes de cada efecto y
recuperación por
client_order_idsin reenvío ambiguo; cancelación durable antes del primer dispatch y modo paper controlado de una sola acción configurada durante una sesión XNYS activa, ambos cerrados por defecto. - máquina de estados IBKR paper detrás de un gateway SDK:
orderRefcausal, estados parciales/terminales explícitos, comisión observada, reprecio y cancelación confirmada, recuperación y stops broker-resident fail-closed. - ciclo durable de stops: target causal por posición, alta, redimensionado y cancelación broker-neutral, persist-before-effect, recuperación sin reenvío y reconciliación exacta antes de cerrar un plan.
- transporte oficial IBKR paper opcional: callbacks de cuenta, instrumentos, órdenes, ejecuciones, comisiones y stops; selección explícita en M6, Gateway gráfico en el host y M6 aislado en Docker sin incorporar artefactos licenciados a las imágenes.
- núcleo M7 broker-neutral: caja y posiciones multimoneda, lotes y exportación
FIFO, NAV con precios/FX explícitos, P&L, costes, reconciliación fail-closed y
persistencia append-only del último
RiskState. - ciclo M7 operativo en proceso independiente: recupera informes terminales del journal M6, reserva cada comando antes de contabilizar, exige caja/contextos de fill/precios/FX explícitos, persiste NAV intradía y un cierre diario único, y activa HALT M5 antes de publicar si la reconciliación es insegura.
- frontera contable causal entre planes M6: compara únicamente caja nativa y
posiciones iniciales contra el último plan
MATCHED; una base obsoleta con fills termina enCAUSAL_CONFLICT/HALT sin NAV ni avance, y los reintentos no duplican fills ni el acuse M5. - replay vertical causal y ejecutable S4→M4→M5→M6→M7: compone el dominio real
contra un fixture BTC/USD sintético fijado por hash, conserva la traza
append-only y recupera tras reinicio sin duplicar fills, caja, stops o NAV.
Su recibo siempre es
audit_only,passed=false: no es un backtest, una puerta cuantitativa ni una prueba paper. - M9 como API y dashboard responsive autenticado con contraseña
scrypt, TOTP, sesión segura, CSRF y WebSocket; proyecta NAV, valoración, P&L/costes yRiskStateoficiales M7, mantiene M6 para actividad y fallback degradado, y consume la cola durable M8 mediante una proyección PostgreSQL M9-owned estrictamente read-only. Los hechos futuros o contradictorios no se muestran parcialmente: la cola quedaUNAVAILABLE. No inventa métricas de retornos. - M8 contra simulador: cola append-only de aportaciones y retiradas, reservas
atómicas por moneda, cinco tramos exactos de 20%, buffer 3/5/10, constraints
monetarios aplicados por M4 y validados por M5 antes de cualquier plan M6,
recovery por identidad y settlement final solo tras el hecho M7 exacto. El
snapshot de caja, el target causal M4, las posiciones y la evidencia de
salida declaran
source=simulator_injected; su validación contra M7 no los convierte en una proyección productiva. - núcleo M11 broker-neutral y append-only para incidentes M5/M6/M7 y la futura M8, watchdog estricto de heartbeats M5/M6, veto M5 y alertas recuperables por identidad, liberación auditada que nunca reabre riesgo y API exclusivamente read-only. Los adaptadores/verificador productivos siguen pendientes.
- auditoría SEC EDGAR raw-first de submissions y CompanyFacts, con CIK, acceptance time y enmiendas point-in-time; el piloto rechazó Stooq antes de descargar precios por licencia y semántica de ajustes incompletas.
- catálogo append-only de adquisiciones, procedencia raw, identidades FIGI y universos point-in-time; orquestadores de Fase 1 para Massive, SEC, Kraken Archive y la auditoría cerrada de rankings cripto.
- D1 raw-first de
index-constitution, siempre audit-only, y D2 source-neutral para incorporar evidencia local de autoridad/corroboración, reconstruir membresía bitemporal con FIGI y publicar atómicamente solo un derivado revisado. InclusoPROMOTED/validation_eligibleconservapassed=false.
ATLAS no garantiza beneficios y todavía no está autorizado para operar con dinero real. Las puertas de validación de la especificación son obligatorias.
Requisitos
- Python 3.12
- Docker con Docker Compose
Puesta en marcha
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install -e '.[dev]'
cp .env.example .env
make check
make smoke
make up
make migrate # aplica migraciones repetibles a volúmenes existentes
make integration-up
make integration
make integration-down
La API queda en http://localhost:8000, Prometheus en
http://localhost:9090, Grafana en http://localhost:3000, el endpoint S3 de
SeaweedFS en http://localhost:8333 y su interfaz de master en
http://localhost:9333. Los procesos internos M5, M6 y M7 escuchan únicamente
en loopback en http://localhost:8001, http://localhost:8002 y
http://localhost:8004, respectivamente. El dashboard M9 se sirve en
http://localhost:8003 y permanece cerrado hasta configurar contraseña y TOTP.
Endpoints iniciales:
GET /health: vida del proceso.GET /ready: conectividad con TimescaleDB y Redis.POST /v1/market-bars: valida y almacena un lote de barras.GET /metrics: métricas Prometheus.
Endpoints internos de M5:
GET :8001/health: vida del proceso independiente de riesgo.POST :8001/v1/risk/evaluate: evalúa un objetivo M4 junto con el snapshot y el estado anterior; devuelve el estado siguiente y la cartera aprobada, recortada o vetada.POST :8001/v1/risk/execution-incidents: convierte un incidente M6 en una decisión HALT que conserva las posiciones protegidas por el broker.
Endpoints internos de M6:
GET :8002/health: vida del proceso independiente de ejecución.GET :8002/ready: heartbeat vigente, journal sin planes inciertos y disponibilidad de PostgreSQL, Redis y M5.GET :8002/heartbeat: estado y edad del último heartbeat de M6.POST :8002/v1/execution/commands: acepta un paquete causal completo ya aprobado por M5, persiste su plan y schedule y devuelve202 Accepted.GET :8002/v1/execution/schedules/{plan_id}: consulta estado, dispatches y el informe terminal cuando esté disponible.GET :8002/metrics: métricas Prometheus del proceso.
Endpoints internos de M7:
GET :8004/ready: disponibilidad de journals M6/M7, tablas operativas y M5.POST :8004/v1/accounting/cycles: contabiliza un ciclo explícito contra un informe M6 terminal durable, valora, reconcilia y persiste su recibo.GET :8004/v1/accounting/nav/latest?kind=intraday|daily_close: recupera el último punto NAV oficial publicado para el libro configurado.GET :8004/metrics: métricas Prometheus del proceso.
Superficie M9:
GET :8003/: aplicación web responsive.POST :8003/v1/auth/login: login con contraseña y TOTP obligatorio.GET :8003/v1/dashboard/snapshot: snapshot autenticado con procedencia por bloque; NAV/cartera/riesgo usan M7 oficial y liquidez lee la cola append-only M8 al mismo cutoff, o cada bloque declara su indisponibilidad.WS :8003/v1/dashboard/live: actualizaciones en vivo autenticadas.POST :8003/v1/dashboard/controls: frontera sensible con CSRF, TOTP y texto de confirmación; permanece fail-closed. Las conexiones read-only de M7 y M8 no habilitan controles, mutaciones de liquidez ni transferencias.
M9 consulta directamente, con SELECT, las tablas append-only de la migración
016 para el libro configurado y el generated_at del snapshot. Valida la
coherencia entre columnas, payload, identidades, secuencia y estado; excluye
hechos futuros y declara siempre transfer_initiated_by_atlas=false. Esta
lectura no convierte las fuentes simulator_injected de M8 en productivas.
Frontera HTTP propia de M8 (todavía no montada en el Compose base ni conectada a controles M9):
GET /healthyGET /ready: vida y disponibilidad del journal 016.GET /v1/liquidity/books/{book_id}/queue?as_of=<UTC>: estado, importe y reserva activa por request; siempre declaratransfer_initiated_by_atlas=false.- No existe endpoint POST ni otra mutación de aportación, retirada, reserva o settlement en esta frontera.
Superficie M11 inicial (factoría implementada, todavía no desplegada en Compose ni asignada a un puerto operativo):
GET /healthyGET /ready: vida, journal y latch global; una resolución no rearma readiness.GET /v1/incidentsyGET /v1/incidents/{incident_id}: lista y detalle append-only.GET /metrics: métricas del proceso.
M11 no expone POST de release, resolve, re-arm ni control. La implementación
actual solo incluye puertos para un ACK M5 durable, una fuente autoritativa de
not_applied, alertas y verificación de operador; sus adaptadores productivos
no existen todavía. Los UUID opacos no son una prueba autovalidada y nunca se
persiste un código TOTP o secreto.
Genera el alta inicial sin guardar secretos en Git:
atlas dashboard-credentials --username atlas
Ejecuta el smoke vertical completamente offline y en memoria:
atlas replay-vertical-s4
La variante durable solo admite el entorno PostgreSQL físicamente aislado:
atlas replay-vertical-s4 --backend isolated-postgres --run-id <uuid>
Consulta el runbook del replay vertical antes de usar esa variante. Nunca conecta con proveedores, IBKR ni cuentas paper/live.
Backfill histórico (requiere el stack levantado y ATLAS_MASSIVE_API_KEY para
acciones/ETFs):
docker compose run --rm ingestion-api atlas backfill \
--provider massive --symbol SPY --asset-class etf \
--from 2025-01-01 --to 2025-12-31 --summary
docker compose run --rm ingestion-api atlas backfill \
--provider kraken --symbol BTC/USD --asset-class crypto \
--from 2026-05-01 --to 2026-08-15
Para construir el artefacto Kraken de Fase 1, descarga su
ZIP OHLCVT oficial,
colócalo en data/archive y calcula su SHA-256:
atlas ingest-kraken-archive \
--archive /data/archive/Kraken_OHLCVT.zip \
--archive-sha256 <sha256-del-zip>
ATLAS archiva y verifica el ZIP entero, captura AssetPairs, fija el inventario
por hash y procesa en bulk los miembros USD resolubles de 240 y 1.440 minutos.
No rellena intervalos sin operaciones y clasifica cada serie como complete,
incomplete o unresolved. El backfill de un miembro individual continúa
disponible para diagnóstico, pero no sustituye esta adquisición de Fase 1.
Cada respuesta se guarda bajo raw/<proveedor>/.../<sha256>.json en el bucket
configurado y se registra en raw_data_manifest antes de crear barras. El
comando compara después el rango con el calendario esperado, repara huecos y
falla si el proveedor no entrega una serie completa. Para Massive sincroniza
además splits y dividendos antes de procesar los precios.
--summary conserva los manifiestos raw y los conteos de auditoría en la salida,
pero evita imprimir miles de fechas cuando se carga un rango amplio.
La auditoría SEC es opt-in y exige una identificación real conforme a Fair Access solo por entorno. No añade factores a M3 ni sustituye OHLCV o constituyentes históricos:
atlas audit-sec-edgar --cik 0000320193
ATLAS usa como máximo 5 peticiones/segundo, conserva accession y aceptación UTC y archiva antes de extraer. Para cargas grandes el adaptador expone los ZIP bulk oficiales. Consulta el informe del piloto antes de evaluar un proveedor de precios.
Los cuatro frentes de proveedor y la semilla de constituyentes de Fase 1 se
ejecutan después de make migrate:
atlas ingest-index-constitution-seed \
--archive /ruta/privada/index_constitution-1.0.0.tar.gz \
--sha256 b214777e37b4d80f9e8484d7d4256eafa6b4e99752da23cc5de4dd83b1a1552c \
--upstream-version 1.0.0 \
--upstream-commit dd1604c5176176f6cf6418c2a4bab0277b51d4ff \
--source-uri https://github.com/unliftedq/index-constitution \
--package-license-id MIT
atlas acquire-massive-core \
--profile stocks-starter-five-calendar-years-v1 \
--end-session 2026-08-21 \
--seed-run-id <uuid-del-run-D1>
atlas audit-sec-edgar --cik 0000320193
atlas ingest-kraken-archive \
--archive /data/archive/Kraken_OHLCVT.zip \
--archive-sha256 <sha256-del-zip>
atlas audit-crypto-rankings
atlas audit-phase1-data
--end-session es una elección explícita del operador: debe ser la última
sesión XNYS ya cerrada que quiera capturar. ATLAS deriva de forma pura la
primera sesión en o después de cinco años naturales antes, conserva el
calendario y el hash de sesiones en el run y rechaza reintentos con otra
ventana. El run_id D1 solo aporta intervalos de captura audit-only; Massive no
crea ni promueve universos. La ruta Stocks Starter rechaza siempre
/etf-global, archiva referencia, eventos de ticker, barras y acciones antes de
normalizar y devuelve código 2 con PRELIMINARY o PARTIAL, nunca una puerta
oficial superada. Véase el ADR 0034.
audit-crypto-rankings no llama a CoinMarketCap: valida la frontera y devuelve
PARTIAL mientras no exista suscripción y confirmación de retención. El informe
conjunto mantiene missing_artifact=crypto_universe; nunca reconstruye el
pasado con rankings actuales. El procedimiento completo está en el
runbook paralelo de datos.
La ingesta index-constitution devuelve deliberadamente PARTIAL (código 2):
solo acepta el CSV hijo después de archivar el sdist padre, no importa el
paquete ni pickles y persiste los intervalos en tablas audit-only separadas. El
SPDX MIT describe el paquete fijado, no demuestra derechos ni procedencia de
cada fila y no cambia su inelegibilidad. El procedimiento y sus conteos de
auditoría están en el
runbook de la semilla y la frontera
se fija en el
ADR 0032.
La ruta D2 no usa esa semilla como autoridad y no realiza descargas. Exige CSV operator-supplied fijados por hash para baseline, feed completo de cambios, corroboración de otra familia y bindings FIGI. Sus tres comandos son:
atlas ingest-equity-constituent-evidence --help
atlas evaluate-equity-constituent-promotion --help
atlas review-equity-constituent-promotion --help
Los derechos insuficientes fallan antes de leer bytes; un known_at tardío no
se retropropaga; una aprobación publica snapshots, miembros y receipt dentro de
una sola transacción. Los esquemas, argumentos obligatorios y códigos de salida
están en el
runbook D2 y la decisión en el
ADR 0036.
Las barras de acciones/ETFs deben declarar adjustment_status como
split_adjusted o total_return_adjusted; una serie unadjusted se rechaza y
marca el activo como no operable. Las barras cripto usan not_applicable.
Las barras diarias se identifican por la fecha de sesión y siempre se almacenan
a las 00:00 UTC, independientemente de la hora que utilice el proveedor.
El replay dorado de M10 verifica tanto el CSV como el resultado esperado:
atlas golden-benchmark --manifest datasets/golden/btcusd_4h_v1.json
Las puertas cuantitativas de la Fase 1 se ejecutan únicamente contra un JSON de
evidencia esquema 2.1 completo y hash-pinned. Cada artefacto declara
evidence_eligibility; un artefacto audit_only impide OFFICIAL_PASSED.
Cada retorno, señal y trade queda dentro de un segmento de proveedor; el
candidato debe estar sellado en el
diario append-only antes de adquirir y ejecutar una sola vez el holdout. La
ausencia de cualquiera de esas pruebas o una puerta fallida devuelve un código
distinto de cero:
atlas validate-phase1 --evidence /ruta/a/phase1-evidence.json
Consulta datasets/validation/README.md, docs/runbooks/m10-evidence-v2.md y docs/phase-1-data-requirements.md. El repositorio no incluye ni simula históricos licenciados o constituyentes point-in-time.
Consulta docs/phase-0.md para los cimientos,
docs/phase-1.md para los criterios del algoritmo y
docs/phase-2.md para el alcance exacto de los incrementos
M6/M7/M9/M11.
El ciclo contable operativo y su recuperación están en
docs/runbooks/m7-operational-accounting.md.
El alta segura y los límites actuales del dashboard están en
docs/runbooks/m9-dashboard.md.
La respuesta fail-closed de M11 y sus fronteras todavía no productivas están en
docs/runbooks/m11-global-incidents.md y
su decisión en
ADR 0039.
La preparación y las puertas pendientes de IBKR están en
docs/runbooks/ibkr-paper.md.
La secuencia de desarrollo posterior a M7/M9/M11, independiente de la prueba
viva, está en docs/development-roadmap.md.
La evaluación gratuita de históricos terminó en FAIL; el procedimiento y el
resultado están en
docs/runbooks/phase1-free-data-pilot.md
y
docs/data-audits/stooq-sec-pilot-2026-08-17.md.
La secuencia posterior conserva Massive cinco años como núcleo de desarrollo y
reserva la historia anterior como holdout de un candidato ya congelado; véanse
ADR 0022, el
runbook del holdout y la
auditoría de los ficheros locales.
El contrato raw-first y las decisiones de universos se fijan en
ADR 0028; el resultado
de implementación y sus bloqueos se separan por proveedor en el
informe de Fase 1.
La decisión de coste vigente descarta el add-on ETF Global Constituents y limita
index-constitution más fuentes abiertas a semillas audit-only hasta su
reconstrucción bitemporal y promoción explícita; véase
ADR 0029.
La implementación D1 de esa decisión permanece separada del universo oficial;
véase ADR 0032.
La reconstrucción/promoción D2 mantiene D1 inmutable y separa promoción de la
puerta cuantitativa; véase
ADR 0036.
El Compose base siempre usa el simulador. El camino paper recomendado ejecuta IB Gateway directamente en la sesión gráfica del host y mantiene M6 y el resto de ATLAS en Docker. Requiere los dos artefactos oficiales aceptados por el usuario, versiones compatibles y login humano:
infra/ibkr/install-host-gateway.sh
infra/ibkr/check-host-versions.sh
infra/ibkr/run-host-gateway.sh
docker compose -f compose.yaml -f compose.ibkr-paper-host.yaml build execution-api
No arranques execution-api con ese overlay hasta completar el login paper,
autorizar la IP privada fija de M6 en Gateway y superar el snapshot sin
órdenes. Ese snapshot requiere datos de mercado en tiempo real habilitados para
API; ATLAS no acepta el feed delayed como sustituto de frescura. El overlay que
contiene Gateway en Docker se conserva como alternativa no operativa; no es la
ruta recomendada actual.
El snapshot vivo ya está validado. La primera orden paper controlada terminó sin exposición porque IBKR rechazó SPY por elegibilidad KID/PRIIPs; consulta el informe operativo.
Flujo de calidad
make format # aplica formato y correcciones seguras
make check # formato, lint, mypy estricto y tests
make compose-config
make integration-up # levanta solo el stack atlas-integration en puertos dedicados
make integration # round trip aislado; rechaza endpoints operativos e IBKR
make integration-down # apaga solo atlas-integration y conserva sus volúmenes
La integración no usa el Compose operativo. Su mapa de recursos, interlocks y procedimiento de diagnóstico están en el runbook de integración aislada.
La configuración de negocio se versiona en
config/atlas.toml. Los secretos solo se suministran por
variables de entorno o por el gestor de secretos del despliegue; nunca se
incluyen en Git.