Atlas20 Rotation is a production-minded crypto research console for testing whether point-in-time top-20 non-stablecoin rotation can outperform BTC buy-and-hold and top-20 equal weight benchmarks.
It is built like an operational research system, not a notebook dump: public data ingestion, reproducible backtests, FastAPI services, a queued worker, Prometheus metrics, OpenAPI contracts, Docker Compose deployment, GHCR images, and a React/Vite console for reviewing results.
Research only. Atlas20 does not provide financial advice and does not execute trades.
- Point-in-time universe construction: top-20 candidates are rebuilt at each rebalance date with explicit stablecoin, wrapped asset, liquidity, and data quality filters.
- Reproducible research pipeline: raw public data, processed datasets, strategy summaries, charts, manifests, and markdown/PDF/bundle reports are generated from versioned YAML configs.
- Console-grade backend: FastAPI routes, SQLModel repositories, Alembic migrations, idempotent run submission, request IDs, rate limits, auth hooks, structured logs, and Sentry-safe redaction.
- Real worker lifecycle: backtests are queued, claimed, heartbeated, cancelled, recovered after stale ownership, and monitored through Prometheus.
- Contract-aware frontend: React/Vite, TanStack Query, generated OpenAPI types, Vitest, axe accessibility tests, and Playwright smoke coverage.
- Ship-ready operations: Docker Compose stack, GHCR images, backup/storage CLIs, health probes, load testing script, and release verification command.
flowchart LR
CG[CoinGecko<br/>candidate universe + metadata]
CC[CryptoCompare<br/>daily prices + volume]
CFG[YAML configs<br/>windows, filters, strategy grid]
PIPE[Research pipeline<br/>universe, regime, backtests]
DB[(SQLite / SQLModel<br/>runs, reports, settings)]
API[FastAPI<br/>OpenAPI, auth, rate limits]
WORKER[Worker process<br/>queue, heartbeat, recovery]
WEB[React/Vite console<br/>overview, studio, compare, reports]
REPORTS[Report artifacts<br/>CSV, PNG, Markdown, PDF, bundle]
METRICS[Prometheus metrics<br/>API + worker scrape targets]
CG --> PIPE
CC --> PIPE
CFG --> PIPE
PIPE --> REPORTS
PIPE --> DB
API <--> DB
API --> WEB
API --> METRICS
WORKER <--> DB
WORKER --> PIPE
WORKER --> REPORTS
WORKER --> METRICS
- Momentum, sector, and benchmark strategy backtests.
- Bull-regime and BTC trailing-stop risk overlays.
- Point-in-time top-20 universe construction from cached public data.
- FastAPI read/write API for the Atlas20 Research Console.
- Background worker for queued backtests and report generation.
- React/Vite web console for champion review, constrained reruns, compare, history, universe health, and reports.
- Prometheus metrics, structured logging, security gates, backup/storage commands, and Docker deployment files.
- Python, API, frontend, accessibility, OpenAPI, mypy, Ruff, and build checks.
Use this when you want the full API, worker, and web stack with the same shape as the published GHCR images.
docker compose up -d
docker compose exec backend python -m atlas20.api.seedThen open:
- API health:
http://127.0.0.1:8000/healthz - API readiness:
http://127.0.0.1:8000/readyz - Worker metrics:
http://127.0.0.1:8001/metrics - Web console:
http://127.0.0.1:5173
Python:
make setup
.venv/bin/python -m atlas20.api.seed
make devmake setup creates .venv and installs the package in editable mode with
development dependencies. Keep Python dependencies inside .venv; do not
install Atlas20 development dependencies into the system interpreter.
Frontend:
npm --prefix apps/web ci
npm --prefix apps/web run devWorker:
PYTHONPATH=src .venv/bin/python -m atlas20.api.workerIn development, Vite proxies /api to http://127.0.0.1:8000.
.venv/bin/python scripts/download_data.py --config config/base.yaml
.venv/bin/python scripts/build_datasets.py --config config/base.yaml
.venv/bin/python scripts/run_research.py --config config/base.yamlPass --refresh-raw to intentionally refresh public API data:
.venv/bin/python scripts/run_research.py --config config/base.yaml --refresh-rawRun the release verification command before publishing:
.venv/bin/python scripts/verify_release.pyThe CI matrix also runs these checks independently:
make test
make lint
make typecheck
.venv/bin/python -m atlas20.api.openapi --check
npm --prefix apps/web test
npm --prefix apps/web run typecheck
npm --prefix apps/web run build
npm --prefix apps/web run openapi:check
.venv/bin/python -m pip_audit --strict .
npm --prefix apps/web audit --audit-level=moderate --registry=https://registry.npmjs.orgmake test runs the Python suite through pytest inside .venv; make lint
and make typecheck run Ruff and mypy through the same virtual environment.
Current local verification for this release line covers 505 Python tests plus 188 Vitest tests, frontend build, strict API mypy, generated OpenAPI types, and Ruff, plus Python and frontend dependency audits.
| Area | Implementation |
|---|---|
| API | FastAPI app factory, OpenAPI snapshot, request IDs, access logs, rate limits |
| Persistence | SQLModel tables, Alembic migrations, repository layer |
| Worker | Queue claim, heartbeat, cancellation, stale-run recovery, subprocess isolation |
| Metrics | Prometheus counters, histograms, worker liveness gauge, /metrics scrape targets |
| Reports | Markdown, CSV, PNG, PDF fallback, zip bundle, manifest verification |
| Deployment | Dockerfile, apps/web/Dockerfile, Docker Compose, GHCR image references |
| Security | API key/JWT hooks, prod settings gates, report path validation, log redaction |
See docs/operations/ for backup, storage, logging, worker, security, and load
testing notes.
.
|-- apps/web/ # React/Vite research console
|-- config/ # Research windows and sector mappings
|-- data/ # Local cached raw/processed public data
|-- docs/ # Design and operations documentation
|-- reports/ # Included research output snapshots
|-- scripts/ # Research, API, verification, and load-test commands
|-- src/atlas20/ # Python package: pipeline, API, worker, backtests
|-- tests/ # Python test suite
|-- pyproject.toml
`-- README.md
- Market cap is used for universe selection only.
- Portfolio construction is not market-cap weighted.
- Strategies allocate by momentum, sector strength, and risk-regime logic.
- The universe is rebuilt point in time at every rebalance date.
- Data assumptions are explicit and documented in generated reports.
- CoinGecko: candidate universe snapshots, market cap snapshot, metadata.
- CryptoCompare: long daily price and dollar-volume history.
- Historical market-cap proxy:
current_market_cap * historical_price / latest_historical_price.
This keeps the project public-data friendly and reproducible. The trade-off is that long-history market-cap ranks are approximations, not perfect historical constituent data.
The end-to-end pipeline writes research artifacts to reports/latest/:
atlas20_report.mdstrategy_summary.csvturnover_summary.csvyearly_returns.csvregime_performance.csvdaily_returns.csvequity_curves.csvdrawdowns.csvequity_curves.pngdrawdowns.pngrolling_12m_returns.pngsector_exposure_<best_sector_strategy>.csvsector_exposure_<best_sector_strategy>.png
Generated console reruns are written to reports/app_runs/ and are ignored by
Git except for the directory placeholder.
Using the cached public-data run included in this workspace:
- Best momentum variant:
TOP20_MOM_top8_biweekly__bull_only - Best sector variant:
TOP20_SECTOR_top3_biweekly__bull_only - BTC buy-and-hold CAGR: about 16.8%
- Top-20 equal-weight CAGR: about -5.0%
- Best momentum CAGR: about 8.1%
- Best sector CAGR: about -0.4%
See reports/latest/atlas20_report.md and the dated report folders for full
interpretation and caveats.
- Long-history market caps are proxied because free public APIs do not reliably expose complete point-in-time daily market-cap history.
- Candidate coverage reduces survivorship bias but is not perfectly survivorship-free.
- Sector labels use human-editable mappings and manual overrides.
- Included results depend on cached data snapshots and should be rerun before making new research claims.
MIT. See LICENSE.