Skip to content

Architecture

System Diagram

Python (TradingNode)
  ├── 5 Strategies  ──── strategy.log.debug(json payload) ──► ./logs/*.json
  └── DatabaseActor ──── self.log.debug(json payload)     ──► ./logs/*.json
                                            Grafana Alloy (tail & parse)
                                                   stage.json  →  stage.labels  →  stage.match
                                                                   │              │
                                                            metric.gauge    metric.counter
                                                                   │              │
                                            Mimir (Prometheus remote_write, persisted on disk)
                                                      Grafana Dashboard (port 3000)

FastAPI (dashboard/)
  └── REST API ──► PostgreSQL

Service Breakdown

engine/

The NautilusTrader node is the core trading runtime. It hosts:

  • 5 strategiesMeanReversionStrategy, HourlyBuyStrategy, and 3 latency-instrumented variants
  • DatabaseActor — persists fills, orders, and signals to PostgreSQL
  • BudgetActor — enforces per-strategy capital caps

Each strategy emits structured JSON log lines consumed by Alloy:

{
  "component_name": "EMACross",
  "metric_type": "gauge",
  "metric_name": "strategy_latency_us",
  "metric_value": 42.5,
  "strategy_id": "mean_reversion"
}

dashboard/

FastAPI server at port 8000. Provides REST endpoints for:

  • Trading data (orders, fills, positions, signals)
  • Budget management (per-strategy capital allocation)
  • Audit logs
  • Docker service management

Observability Stack

Service Port Role
Grafana Alloy 12345 Tail logs, parse JSON, emit Prometheus metrics
Mimir 9009 Prometheus-compatible metrics storage
Grafana 3000 Dashboards and alerting
Loki 3100 Log aggregation
cAdvisor 8080 Container CPU/memory/network metrics

Metric Flow

Log line (JSON in message field)
  └── Alloy stage.json  →  extracts metric_type / metric_name / metric_value / strategy_id
      └── stage.labels  →  promotes to stream labels
          ├── {metric_type="gauge"}   →  loki_process_custom_nautilus_latency_us
          └── {metric_type="counter"} →  loki_process_custom_nautilus_metrics_this_run_total

Note

Counters reset when Alloy restarts. Use increase(metric[duration]) in PromQL for windowed counts. For authoritative totals, query the database directly.

Docker Compose Files

File Purpose
docker-compose.dev.yml Local dev: PostgreSQL 18 + Redis only
docker-compose.yml Observability stack: Mimir, Alloy, Grafana, Loki, cAdvisor
docker-compose.prod.yml Production overlay: adds trader container