fd-paper-trading MCP Server
OfficialREADME.md
<div align="center">
**Part of the [Wire line (寻数·柏讯)](https://www.finddatatech.cloud/products/wire) of [FindData](https://www.finddatatech.cloud)** — the B2B data platform line.
[English](./README.md) · [简体中文](./README.zh-CN.md)
</div>
# fd-paper-trading
Multi-tenant **paper-trading** service exposed via a FastAPI REST + WebSocket API and an MCP server. Users can own multiple paper trading accounts and place orders through the API against real-time market data with **simulated fills** — no broker, no real capital.
## Features
- **Multi-user auth** — JWT + revocable API tokens (`fdt_` prefix)
- **Multi-account management** — each user can create and manage multiple isolated paper accounts
- **Order execution** — market and limit orders with simulated fills via a stateless pure-Python fill calculator
- **Position & cash ledgering** — real-time P&L, average cost, realized gains
- **Real-time streaming** — WebSocket endpoint (`/ws`) pushes live quotes, order-status, and fill events
- **MCP server** — 19 tools (accounts, orders, positions, instrument search, bars, strategy lifecycle) on stdio and streamable HTTP. Caller identity is delegated: HTTP callers present their own `Authorization` credential and act as themselves on a shared deployment; stdio falls back to the configured token
- **Market data** — `SimulatedMarketDataProvider` (deterministic, for dev/tests), `PolygonMarketDataProvider` (real prices, end-of-day on free tier), and `FdOpenDataMarketDataProvider` (real daily bars + close-derived quotes from the [fd-open-data-mcp](https://github.com/FindDataTechnology/fd-open-data-mcp) ontology)
- **Quant strategies** - dual-track authoring: fixed templates (SMA cross, RSI reversion, Bollinger breakout, MACD cross, DCA) and sandboxed custom code (`on_bar(ctx)`); backtest with equity-curve stats; live paper runs that place attributed signals on your account. Per-user group limits (active strategies, daily orders, custom-code gate, symbol allowlist)
- **Web UI** — React + TypeScript SPA with professional trading dashboard featuring:
- **Three-column workspace**: watchlist (live quotes), price chart, and order panel
- **Click-to-trade**: select any symbol from watchlist to instantly update chart and order form
- **Position management**: quick close/reduce actions with confirmation dialogs
- **Daily P&L tracking**: real-time calculation from realized + unrealized components
- **Strategies pages**: create/edit strategies (template param form or code editor), run backtests with equity curves, and monitor live paper runs + history
- **Typeahead symbol search**, interactive charts (TradingView `lightweight-charts`), and live streaming
## Tech Stack
- **Backend:** Python 3.12+, FastAPI + Uvicorn, SQLAlchemy 2.0 async, Alembic
- **Database:** PostgreSQL (prod) / SQLite (tests)
- **Auth:** JWT (`python-jose`) + bcrypt + revocable API tokens
- **Execution:** stateless pure-Python fill calculator (no trading framework)
- **Frontend:** React 18 + TypeScript + Vite, TanStack Query + Zustand, TradingView `lightweight-charts`
- **Testing:** pytest (backend), Vitest + React Testing Library (frontend), Playwright (e2e)
## Quick Start
```bash
# 1. Install Python dependencies
uv sync
# 2. Configure environment
cp .env.example .env # edit DATABASE_URL, JWT_SECRET, market-data keys
# 3. Provision PostgreSQL and apply migrations
brew services start postgresql@14
createdb paper_trading
uv run alembic upgrade head
# 4. (Optional) Build the web UI so FastAPI serves it at /
cd web && npm install && npm run build && cd ..
# 5. Run the API (OpenAPI docs at http://localhost:8000/docs)
uv run fd-paper-trading
```
> **Note:** On macOS with Homebrew, `postgresql@14` may run on port 5433 if 5432 is occupied. Adjust `DATABASE_URL` in `.env` accordingly.
> **Admin bootstrap:** to manage user groups (custom-code access, symbol allowlists, limits), set `FD_ADMIN_EMAILS=you@example.com` in `.env` and register with that email - the account is promoted to admin. Admins manage groups at `POST /api/v1/groups` and assign users at `POST /api/v1/users/{id}/group`.
### fd-open-data market data (optional)
To trade/backtest on real daily bars from the [fd-open-data-mcp](https://github.com/FindDataTechnology/fd-open-data-mcp) ontology instead of simulated quotes:
```bash
# One-time bootstrap of the ontology DB (migrate, catalog import, concepts,
# bindings, entity seeds). Set FD_OPEN_DATA_MCP_DATABASE_URL to override the
# default sqlite location.
uv run python scripts/setup_fd_open_data.py
# Then select the provider
MARKET_DATA_PROVIDER=fd-open-data uv run fd-paper-trading
```
The bootstrap prints a coverage report mapping the curated symbol universe to ontology entity IDs; unresolved symbols return no bars/quotes until the ontology seeds them (e.g. via the library's `migrate-astock-daily` or entity import commands).
**Concept family** — the provider reads one concept, configured as code/entity-type/frequency (default `nav.unit`/`fund`/`daily` — fund NAV, the family with real production data, updated daily). `CRYPTO_*` and `IDX_*` concepts are live in the catalog but currently carry no observations:
```bash
FD_OPEN_DATA_CONCEPT=CRYPTO_PRICE FD_OPEN_DATA_ENTITY_TYPE=symbol MARKET_DATA_PROVIDER=fd-open-data uv run fd-paper-trading
```
A deprecated concept degrades to a data gap (no bars, no quotes), never an error. The stock `price.*` family is deprecated by curation policy and must not be re-registered.
### Development
```bash
# Terminal 1: FastAPI backend on :8000
uv run fd-paper-trading
# Terminal 2: Vite dev server on :5173 (proxies /api and /ws to backend)
cd web && npm install && npm run dev
```
### Production
```bash
# Build the SPA and serve everything from FastAPI on a single origin
cd web && npm run build
uv run fd-paper-trading # SPA + API + /ws all at http://localhost:8000/
```
## Architecture
```
┌─────────────────────────────────────────────────────────┐
│ Web UI (React + Vite + TypeScript) │
│ - TanStack Query for data fetching │
│ - Zustand for state management │
│ - TradingView lightweight-charts for charting │
│ - WebSocket client for real-time streaming │
└────────────────────┬────────────────────────────────────┘
│ REST (/api/v1) + WebSocket (/ws)
┌────────────────────▼────────────────────────────────────┐
│ FastAPI Backend │
│ - Auth (JWT + API tokens) │
│ - Account management │
│ - Order placement & cancellation │
│ - Position & cash ledgering │
│ - Market data API │
└────────────────────┬────────────────────────────────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│PostgreSQL│ │ Filling │ │ Market │
│(ledger) │ │ (fills) │ │ Data │
└──────────┘ └──────────┘ └──────────┘
```
**Execution model (v1):** Fills are computed by a stateless pure-Python calculator (one quote + one order in, fill outcome out). Account state lives in the database, isolated by `account_id`.
## Trading Dashboard
The web UI provides a professional trading workspace optimized for active trading:
```
┌───────────────────────────────────────────────────────────────┐
│ Watchlist (left) │ Price Chart │ Order Ticket (right) │
├──────────────────┼──────────────┼─────────────────────────────┤
│ AAPL $175.50▲│ │ Side: [Buy ▼] Sell │
│ TSLA $250.20▼│ │ Type: [Market ▼] Limit │
│ NVDA $890.10▲│ [graph] │ Qty: [100] Limit:$175 │
│ SPY $450.00▶│ │ │
│ QQQ $400.25▶│ │ [BUY AAPL] [SELL AAPL] │
│ Total PnL: (+$127)│ │
├──────────────────┴──────────────┴─────────────────────────────┤
│ Positions Table (quick close/reduce buttons on each row) │
└───────────────────────────────────────────────────────────────┘
```
**Key features:**
- **Watchlist**: Live quotes for tracked symbols (AAPL, TSLA, NVDA, SPY, QQQ), updated via WebSocket
- **Click-to-trade**: Click any symbol in the watchlist to instantly update the chart and order panel
- **Order panel**: Always-visible order entry form bound to the selected symbol
- **Position actions**: Quick close/reduce buttons with confirmation dialogs
- **Daily P&L**: Real-time calculation from realized gains + unrealized mark-to-market
**Note:** Daily P&L is indicative (frontend-calculated) and may differ slightly from backend calculations. Mobile-responsive layout and user-configurable watchlists are planned for future releases.
## Commands
```bash
# Backend
uv run pytest # all backend tests (in-memory SQLite)
uv run pytest tests/unit/ # unit tests only
uv run pytest tests/e2e/ # end-to-end flows only
uv run alembic upgrade head # apply database migrations
uv run alembic downgrade -1 # rollback last migration
# Frontend
cd web && npm test # Vitest component tests
cd web && npx playwright test # Playwright e2e tests
cd web && npm run build # production build
cd web && npm run dev # dev server with hot reload
```
## API Overview
| Method | Path | Description |
|---|---|---|
| POST | `/api/v1/auth/register` | Register a user |
| POST | `/api/v1/auth/login` | Obtain a JWT access token |
| POST | `/api/v1/tokens` | Create a revocable API token |
| GET | `/api/v1/tokens` | List API tokens |
| DELETE | `/api/v1/tokens/{id}` | Revoke an API token |
| GET | `/api/v1/accounts` | List your accounts |
| POST | `/api/v1/accounts` | Create a paper account |
| GET | `/api/v1/accounts/{id}` | Account summary (balance, equity, counts) |
| POST | `/api/v1/accounts/{id}/deposit` | Deposit / withdraw (signed amount) |
| POST | `/api/v1/accounts/{id}/reset` | Reset account (cancel orders, flatten, restore balance) |
| GET | `/api/v1/accounts/{id}/positions` | List open positions |
| GET | `/api/v1/accounts/{id}/orders` | List orders (optional `?status=`) |
| POST | `/api/v1/orders` | Place a market/limit order (simulated fill, returns 202) |
| DELETE | `/api/v1/orders/{id}` | Cancel an open order |
| GET | `/api/v1/orders/{id}` | Query a single order |
| GET | `/api/v1/instruments/search?q=` | Search instruments by symbol/name |
| GET | `/api/v1/instruments/{symbol}/bars` | Historical OHLCV bars (`?timeframe=&limit=`) |
| WS | `/ws` | Stream quotes + order/fill events (auth in first message) |
**Authentication:** `Authorization: Bearer <jwt>` or `Authorization: Bearer <api-token>` (tokens start with `fdt_`).
**WebSocket:** Send `{"type":"auth","token":"<jwt>"}` as the first message, then `{"type":"subscribe","symbol":"AAPL"}` / `{"type":"unsubscribe","symbol":"AAPL"}`.
**Errors:** Standardized format: `{"error": {"code": "...", "message": "...", "fields": [...]}}`.
## Contributing
1. Fork the repository
2. Create a feature branch: `git checkout -b feature/your-feature`
3. Make your changes and add tests
4. Run the test suite: `uv run pytest && cd web && npm test`
5. Commit with a descriptive message: `git commit -m "Add your feature"`
6. Push to your fork: `git push origin feature/your-feature`
7. Open a Pull Request
Please ensure your code follows the existing style and all tests pass before submitting.
## License
MIT — see [LICENSE](./LICENSE).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues