# docker-compose.yml — Multi-Swarm Coevolutive # # Due servizi che condividono la stessa immagine `multi-swarm:dev`: # # * multi-swarm-paper — paper-trading runner long-running # (scripts/run_paper_trading.py) # * multi-swarm-dashboard — Streamlit dashboard esposta da Traefik # su https://swarm.${DOMAIN_NAME:-tielogic.xyz} # # Entrambi joinano la rete external `traefik` cosi' il client Cerbero # risolve direttamente l'host `cerbero-mcp` (porta 9000) senza passare # dal gateway pubblico ne' dal TLS. # # Dati persistenti via bind mount dalla cartella del repo: # ./data cache OHLCV intermedia # ./series cache parquet per timeframe/symbol # ./state contiene runs.db (+ WAL/SHM) # ./strategies btc_*.json / eth_*.json letti dal paper runner # # Secrets (token Cerbero + OpenRouter): caricati da .env via env_file. # Le variabili sotto `environment:` sovrascrivono solo i valori che # devono cambiare dentro il container (URL interno, path container). networks: traefik: external: true x-swarm-env: &swarm-env # Override: rotta interna verso cerbero-mcp (no TLS, no traefik hop) CERBERO_BASE_URL: http://cerbero-mcp:9000 # Override: path container per persistenza DATA_DIR: /app/data SERIES_DIR: /app/series DB_PATH: /app/state/runs.db services: multi-swarm-paper: build: context: . dockerfile: Dockerfile image: multi-swarm:dev container_name: multi-swarm-paper restart: unless-stopped networks: [traefik] env_file: .env environment: <<: *swarm-env volumes: - ./data:/app/data - ./series:/app/series - ./state:/app/state - ./strategies:/app/strategies:ro # Niente HTTP da controllare: ci affidiamo a `restart: unless-stopped` # e ai log per la liveness del runner. command: - python - /app/scripts/run_paper_trading.py - --name=${PAPER_RUN_NAME:-phase3-papertrade-prod} - --initial-capital=${PAPER_INITIAL_CAPITAL:-1000} - --fees-bp=${PAPER_FEES_BP:-5.0} - --poll-seconds=${PAPER_POLL_SECONDS:-300} - --lookback-bars=${PAPER_LOOKBACK_BARS:-500} - --strategies-dir=/app/strategies labels: - com.centurylinklabs.watchtower.enable=true multi-swarm-dashboard: image: multi-swarm:dev build: context: . dockerfile: Dockerfile container_name: multi-swarm-dashboard restart: unless-stopped networks: [traefik] env_file: .env environment: <<: *swarm-env volumes: # Dashboard legge solo runs.db: mount in read-only - ./state:/app/state:ro - ./data:/app/data:ro - ./series:/app/series:ro entrypoint: - streamlit - run - /app/src/multi_swarm/dashboard/streamlit_app.py - --server.address=0.0.0.0 - --server.port=${SWARM_DASHBOARD_PORT:-8501} - --server.headless=true - --browser.gatherUsageStats=false command: [] healthcheck: test: - "CMD" - "python" - "-c" - "import os, urllib.request; urllib.request.urlopen(f'http://localhost:{os.environ.get(\"SWARM_DASHBOARD_PORT\",\"8501\")}/_stcore/health', timeout=3).close()" interval: 30s timeout: 5s retries: 3 start_period: 30s labels: - traefik.enable=true - traefik.docker.network=traefik - "traefik.http.routers.multi-swarm-dashboard.rule=Host(`swarm.${DOMAIN_NAME:-tielogic.xyz}`)" - traefik.http.routers.multi-swarm-dashboard.tls=true - traefik.http.routers.multi-swarm-dashboard.entrypoints=websecure - traefik.http.routers.multi-swarm-dashboard.tls.certresolver=mytlschallenge - "traefik.http.services.multi-swarm-dashboard.loadbalancer.server.port=${SWARM_DASHBOARD_PORT:-8501}" - com.centurylinklabs.watchtower.enable=true