Admin-only crypto quant trading scaffold built for a Backpack-first integration model.
- Frontend: React + TypeScript + Vite + Tailwind
- Backend: FastAPI + Python
- Database: PostgreSQL
- Runtime: local commands or
docker compose
The backend is prepared for two data modes:
BACKPACK_MODE=mock: local fixture data for UI developmentBACKPACK_MODE=live: real REST calls to Backpack Exchange
When live is enabled, set:
ADMIN_API_TOKENALLOW_INSECURE_DEV_DEFAULTS=falseBACKPACK_API_BASE_URLBACKPACK_API_KEYBACKPACK_PRIVATE_KEYBACKPACK_WINDOW_MSBACKPACK_DEFAULT_SYMBOLBACKPACK_DEFAULT_INTERVALBACKPACK_DEFAULT_PRICE_SOURCEBACKPACK_DEFAULT_MARKET_TYPEBACKPACK_ACCOUNT_LABEL
Profile: summary, asset balances, open positions, account event ledgerStrategy Lab: template and script strategies under one normalized contractBacktests: K-line backtests with open/close markersMarket Pulse: feed freshness and market semanticsExecution: future live-ready order lifecycle skeletonRisk Controls,Alerts,Settings
- Explicit
priceSource = last | mark | index - Database time standard is
timestamptz - Account activity is modeled as an event ledger
- Execution identity is split between
clientOrderIdandexchangeOrderId - Strategy scripts are expected to run inside a deterministic restricted Python runtime
src/: frontend admin consolebackend/app/: FastAPI app and typed response schemasbackend/sql/001_initial_schema.sql: normalized PostgreSQL schemadocker-compose.yml: local frontend + backend + postgres stack
All /api/* routes require an X-Admin-Token header that matches ADMIN_API_TOKEN. Missing tokens return 401; invalid tokens return 403. /healthz stays public.
GET /api/profile/summaryGET /api/profile/assetsGET /api/profile/positionsGET /api/profile/account-eventsGET /api/strategiesGET /api/backtests/:idGET /api/markets/:symbol/klinesGET /api/markets/pulseGET /api/alertsGET /api/settings/accountsGET /api/agent/capabilitiesGET /api/agent/contextPOST /api/strategies/templates/:template_id/backtestsPOST /api/strategies/scripts/:strategy_id/backtests
Backtest runs now follow an explicit lifecycle:
POST /api/strategies/.../backtestscreates a run and returns an id plusresultPathGET /api/backtests/:idretrieves the normalized result payload
The admin UI now uses that same flow for its preview run instead of reading a singleton demo response directly.
cp .env.example .env
npm install
npm run dev.env.example intentionally opts into weak local-only secrets with ALLOW_INSECURE_DEV_DEFAULTS=true. Outside local development or tests, unset that flag and provide a real ADMIN_API_TOKEN, a non-default DATABASE_URL, and, for live mode, real Backpack credentials. Startup now fails fast when those requirements are not met.
Backend:
python3 -m venv .venv
. .venv/bin/activate
PIP_INDEX_URL=https://pypi.org/simple pip install -r backend/requirements.txt
uvicorn backend.app.main:app --reload --host 0.0.0.0 --port 8000Frontend admin access:
- The React shell will not render until an admin token is entered.
- The token is stored in
sessionStoragefor the current browser session only. - The frontend attaches the token as
X-Admin-Tokenon every backend API request.
To switch from mock data to Backpack live mode:
cp .env.example .env
# fill BACKPACK_API_KEY and BACKPACK_PRIVATE_KEY
BACKPACK_MODE=live uvicorn backend.app.main:app --reload --host 0.0.0.0 --port 8000Compose:
docker compose up --builddocker compose now requires explicit DATABASE_URL, ADMIN_API_TOKEN, and POSTGRES_PASSWORD values from .env rather than silently falling back to weak secrets.
Frontend: http://localhost:5173
Backend docs: http://localhost:8000/docs
- PostgreSQL remains the source of truth for balances, positions, backtests, execution state, risk rules, and audits.
- Backpack signing uses ED25519 credentials from environment variables; do not commit real keys.
BACKPACK_PRIVATE_KEYshould be provided only through local env or secret injection, never hardcoded.- Secrets are intended to be encrypted at rest and never re-shown after write.