Files
momentum-system/dashboard_api.py
T
momentum devandClaude Opus 4.8 f0fb91a069 Admin panel (:8767): config, profiles, service control, paper/live switch
New admin service — LAN-only, token-authed (ADMIN_TOKEN), card-based UI
matching the owner's preferred dashboard style. Capabilities:
- health: docker containers via /var/run/docker.sock (stdlib unix-socket
  HTTP client), DB heartbeat, Alpaca account/clock, Ollama, feed
- config: whitelisted strategy knobs (TRADING_/TRIGGER_/WATCHER_/...)
  edited via data/overrides.env, which every entrypoint now loads with
  override=True at boot (runtime/env_overrides.py) — so changes apply on
  container restart without touching the deployment YAML; secrets are
  presence-only and rejected server-side if edited
- profiles: named knob presets (seeded: validated-core, conservative,
  squeeze-hunter) applied in one click
- restart buttons per container; paper/live switch guarded behind
  ALPACA_LIVE_* keys existing
Verified live in docker: auth 401s, status/config/profiles/write paths,
secret-edit rejection, page serves. Added to both compose files.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 18:37:18 -04:00

49 lines
1.8 KiB
Python

"""Run the dashboard API + UI standalone (read-only against the event DB).
python dashboard_api.py
# open http://127.0.0.1:8010
Env: DASHBOARD_HOST, DASHBOARD_PORT, WATCHER_EVENT_DB_PATH,
TRADING_EXECUTION_MODE. For approve/reject/exit buttons to act, run the full
orchestrator (run_live_paper.py) instead, which attaches the execution
service to this same server.
"""
from __future__ import annotations
import os
from dotenv import load_dotenv
# Load .env so DATABASE_URL resolves to the configured Postgres (e.g.
# 192.168.1.5:5432) — the event store reads it. Without this the standalone
# dashboard fell back to the legacy local DuckDB path and showed nothing.
load_dotenv()
from runtime.env_overrides import load as _load_overrides
_load_overrides() # admin-panel overrides beat compose env
from api.main import DashboardState, create_server # noqa: E402
def main() -> None:
host = os.environ.get("DASHBOARD_HOST", "0.0.0.0")
port = int(os.environ.get("DASHBOARD_PORT", "8765"))
# The datastore is Postgres (DATABASE_URL); the event store reads it directly.
# WATCHER_EVENT_DB_PATH is a legacy fallback only (the path is ignored).
db_path = os.environ.get("DATABASE_URL") or os.environ.get(
"WATCHER_EVENT_DB_PATH", "momentum")
mode = os.environ.get("TRADING_EXECUTION_MODE", "alpaca_paper")
state = DashboardState(db_path, execution_service=None, execution_mode=mode)
server = create_server(state, host, port)
db_disp = db_path.split("@")[-1] if "@" in db_path else db_path
print(f"[dashboard] serving http://{host}:{port} (event db: {db_disp}, mode: {mode})")
print("[dashboard] read-only mode — run run_live_paper.py for live actions")
try:
server.serve_forever()
except KeyboardInterrupt:
print("\n[dashboard] stopped")
if __name__ == "__main__":
main()