Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/deniszidbaev-cmyk/polyclaw-trading/llms.txt

Use this file to discover all available pages before exploring further.

The Mission Control dashboard is a read-only Flask application that gives you a live view of your trading engine’s state — equity, realized P&L, drawdown, open exposure, signals, and the execution ledger — all served directly from the runtime/*.json files that the pipeline stages write. It never reads .env.local, never touches wallet keys or OpenClaw configuration, and never invokes any trading command.

Starting the dashboard

# Direct Python invocation:
uv run python bot/dashboard/app.py

# Or via Docker Compose (from the repo root):
docker compose up --build
On startup, the dashboard prints its bind address:
=== PolyClaw Mission Control ===
URL: http://127.0.0.1:8080
Read-only runtime monitor. Press Ctrl+C to stop.

Default binding: loopback only

By default, the dashboard binds to 127.0.0.1:8080. This means it is only reachable from the same machine. Requests from any other host are refused at the network level.
Before changing DASHBOARD_HOST to any non-loopback address (e.g., 0.0.0.0 or a LAN IP), you must set DASHBOARD_AUTH_TOKEN to a strong random secret. If you set a non-local host without a token, the server will print a warning and force the bind address back to 127.0.0.1. Exposing an unauthenticated dashboard to a network gives any visitor a read-only view of your equity, positions, and execution history.

Configuration

VariableDefaultDescription
DASHBOARD_HOST127.0.0.1Bind host. Non-loopback values require DASHBOARD_AUTH_TOKEN.
DASHBOARD_PORT8080TCP port to listen on.
DASHBOARD_AUTH_TOKEN(empty — no auth)Bearer token or X-Auth-Token value required on all routes except / and /health.
Set these in .env.local:
# .env.local

# Expose on all interfaces (requires a token):
DASHBOARD_HOST=0.0.0.0
DASHBOARD_PORT=8080
DASHBOARD_AUTH_TOKEN=your-secret-token-here

Authentication

When DASHBOARD_AUTH_TOKEN is set, all routes except the root (/) and /health require the token in one of two headers:
# Bearer token (standard Authorization header):
curl -H "Authorization: Bearer your-secret-token-here" http://127.0.0.1:8080/api/stats

# X-Auth-Token header (alternative):
curl -H "X-Auth-Token: your-secret-token-here" http://127.0.0.1:8080/api/stats
The token comparison uses hmac.compare_digest to prevent timing attacks. A missing or incorrect token returns HTTP 401:
{"error": "unauthorized"}

API endpoints

GET /health

Health check — no authentication required. Returns 200 when bankroll_state.json and trade_gate_status.json are present and fresh; 503 when they are missing or stale.

GET /api/stats

Consolidated KPIs: equity, working bank, daily budget, daily spend, P&L (total and today), win rate, active positions, exposure, drawdown, risk multiplier, execution mode, and candidate markets.

GET /api/positions

Current open positions from runtime/open_positions_snapshot.json, including market name, side, size, price, and unrealized P&L.

GET /api/history

Recent execution history from runtime/trade_history.json or the latest runtime/executions/YYYYMMDD.json. Includes status (dry_run, executed, failed), conviction, and P&L.

GET /api/decisions

Current decisions from runtime/decisions.json: market, direction, amount, confidence, strategy, timeframe, and reason.

GET /api/equity

Equity history from runtime/equity_history.json — up to the last 180 data points with equity, working bank, reserve, and drawdown percentage.

/api/sources — Source freshness

curl http://127.0.0.1:8080/api/sources
Returns the freshness status of every tracked runtime/*.json file:
[
  {
    "name": "bankroll_state.json",
    "available": true,
    "age_seconds": 47,
    "fresh": true,
    "stale_after_seconds": 600
  },
  {
    "name": "decisions.json",
    "available": true,
    "age_seconds": 312,
    "fresh": true,
    "stale_after_seconds": 600
  }
]
A source is considered stale when its age_seconds exceeds max(600, SIGNAL_INTERVAL_SEC × 2). The /api/stats endpoint reflects this: a stale bankroll_state.json or trade_gate_status.json sets "block_reason": "stale_runtime".

Security design

The dashboard enforces several layers of protection: Strict filename whitelist. Runtime filenames are validated against the regex ^[A-Za-z0-9._-]+\.json$ before being joined to the runtime root, and consecutive dots are explicitly rejected. This prevents path traversal attacks — a dynamically resolved filename can never escape the runtime/ directory. Response size cap. Each JSON file is capped at 10 MB before being read. Oversized files are treated as unavailable. Security headers. Every response includes a Content Security Policy with per-request nonces, X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy: no-referrer, and a Permissions-Policy that disables camera, microphone, and geolocation. No secrets in scope. The dashboard process never reads .env.local, OpenClaw configuration, wallet private keys, or any file outside runtime/. It cannot invoke trading commands.

What the dashboard reads

The dashboard reads the following runtime/ files:
FileEndpoint(s)
bankroll_state.json/api/stats, /health
trade_gate_status.json/api/stats, /health
market_analysis.json/api/stats
open_positions_snapshot.json/api/stats, /api/positions
trade_history.json/api/stats, /api/history
decisions.json/api/decisions, /api/sources
equity_history.json/api/equity, /api/sources
executions/YYYYMMDD.json/api/history (fallback)
If bankroll_state.json and trade_gate_status.json have not been generated yet (e.g., before the first pipeline run), the dashboard falls back to legacy SQLite metrics from data/bot.db. This backwards-compatibility path is labeled "source_mode": "legacy_sqlite" in the /api/stats response.

Checking dashboard health

# No auth token required:
curl http://127.0.0.1:8080/health
Example response when the runtime is ready and fresh:
{
  "status": "ok",
  "runtime_ready": true,
  "runtime_fresh": true,
  "auth_enabled": false
}
When runtime_ready is false, the HTTP status code is 503. Use this endpoint for Docker health checks or uptime monitoring without exposing authenticated routes.

Build docs developers (and LLMs) love