## File: README.md

> QuantDinger can submit real orders when live trading is explicitly enabled.
> Start with paper trading, use restricted API keys, and review the risk and
> compliance requirements for your jurisdiction. This project does not provide
> investment advice.

## What QuantDinger is

QuantDinger is an **open-source AI Trading OS** for independent traders, Python
strategy authors, and small teams. Its local-first, self-hosted design keeps
market data, strategy code, broker credentials, and deployment under the
operator's control.

The project combines:

- multi-provider AI market research and analysis;
- Python indicators and Strategy API V2 development;
- server-side backtesting and experiment workflows;
- paper and live execution across crypto exchanges and traditional brokers;
- web, mobile H5, human API, Agent Gateway, and MCP access;
- PostgreSQL-backed state, durable workers, audit logs, and optional monitoring.

It is not a black-box signal service. Strategy code, risk settings, credentials,
and deployment remain under the operator's control.

## What changed in v5

The v5 backend is organized around explicit runtime and operational boundaries:

- the HTTP API no longer owns long-running trading or scheduler loops;
- trading, scheduling, Celery jobs, and migrations run as separate processes;
- Celery handles finite, retryable work while long-lived strategy runtimes stay
  in the trading worker;
- cache Redis and durable job Redis use separate instances and eviction policies;
- high-risk API contracts are represented in OpenAPI and protected by tests;
- JSON logs, request IDs, Prometheus metrics, dashboards, and alert rules are
  available through an optional observability overlay;
- the production overlay runs backend processes as a non-root user with a
  read-only root filesystem, dropped capabilities, and resource limits;
- CI checks syntax, lint, tests, release gates, Compose files, dependencies,
  source security, secrets, API compatibility, version drift, and text encoding.

The source version is declared in [`VERSION`](VERSION). Git release tags use the
same semantic version with a leading `v`, for example `v5.0.1`.

## Architecture





The diagram above shows the complete product and process architecture. The
runtime topology below focuses on container-to-container ownership and data flow.

```mermaid
flowchart TB
    C["Web / Mobile / API / MCP clients"]
    FE["Nginx frontend services"]
    API["Flask + Gunicorn API"]
    PG[("PostgreSQL")]
    CACHE[("Redis cache")]
    JOBS[("Redis jobs")]
    TW["Trading worker"]
    SW["Scheduler worker"]
    CW["Celery worker"]
    BEAT["Celery beat"]
    PROM["Prometheus"]
    GRAF["Grafana"]
    ALERT["Alertmanager"]

    C --> FE --> API
    API --> PG
    API --> CACHE
    API -->|"durable commands"| PG
    TW -->|"leases, orders, heartbeats"| PG
    SW -->|"schedules, monitoring, heartbeats"| PG
    API -->|"finite async jobs"| JOBS
    BEAT --> JOBS --> CW
    CW --> PG
    API -. metrics .-> PROM
    PG -. exporter .-> PROM
    CACHE -. exporter .-> PROM
    JOBS -. exporter .-> PROM
    PROM --> GRAF
    PROM --> ALERT
```

One backend image is reused by several containers with different commands:

| Process | Responsibility |
| --- | --- |
| `migration` | Applies the database schema and exits before application services start. |
| `backend` | Handles HTTP, authentication, validation, and durable command submission. |
| `trading-worker` | Owns strategy runtimes, pending orders, broker sessions, and reconciliation. |
| `scheduler-worker` | Runs portfolio, deployment, payment, and signal schedules. |
| `celery-worker` | Executes finite AI, backtest, experiment, report, and maintenance jobs. |
| `celery-beat` | Dispatches periodic Celery tasks. |

See [Backend process roles](docs/architecture/PROCESS_ROLES_AND_TASKS.md),
[architecture](docs/architecture/ARCHITECTURE.md), and
[concurrency model](docs/architecture/CONCURRENCY_MODEL.md) for the ownership rules.

## Quick start

### Option A: prebuilt images

Prerequisites: Docker with Compose v2. Node.js and a local Python environment are
not required.

Linux or macOS:

```bash
curl -fsSL https://raw.githubusercontent.com/OpenByteInc/QuantDinger/main/install.sh | bash
```

Windows PowerShell:

```powershell
irm https://raw.githubusercontent.com/OpenByteInc/QuantDinger/main/install.ps1 | iex
```

The installer asks for the initial administrator credentials, generates the
required secrets, downloads the GHCR Compose stack, and starts it.

Open:

- Web: <http://127.0.0.1:8888>
- Mobile H5: <http://127.0.0.1:8889>
- API health: <http://127.0.0.1:5000/api/health>

### Docker administrator and settings notes

Detailed guides: [English](docs/deployment/ADMIN_AND_SETTINGS_TROUBLESHOOTING_EN.md) |
[中文](docs/deployment/ADMIN_AND_SETTINGS_TROUBLESHOOTING_CN.md)

On a fresh database, the backend creates the initial administrator from
`ADMIN_USER`, `ADMIN_PASSWORD`, and optional `ADMIN_EMAIL`. Passwords are stored
as hashes, never as plaintext. An existing PostgreSQL volume is not overwritten:
the backend only replaces the untouched legacy `quantdinger` / `123456`
administrator when a non-default administrator is explicitly configured. It
never overwrites an account whose password was already changed, and it refuses
to promote an existing account that already uses the requested username.

Manual Docker deployments retain `quantdinger` / `123456` only for backward
compatibility when the administrator variables are left at their defaults. This
credential is not suitable for an internet-facing deployment; change it before
first start or immediately after the first login. The one-command installer does
not accept `123456` as the chosen password.

The Settings UI writes runtime configuration to `/app/.env`. In the GHCR stack
this is the host `backend.env`; in a source deployment it is
`backend_api_python/.env`. Current backend images automatically give runtime UID
`10001` ownership and keep mode `600`. Do not use `chmod 755` or recursive `777`:
these files contain passwords and API keys, and `755` still does not grant write
access to UID `10001` when root owns the file.

Verify write access with:

```bash
docker compose exec -u 10001:10001 -T backend \
  sh -c 'test -w /app/.env && echo writable=yes || echo writable=no'
```

The hardened production override intentionally mounts `/app/.env` read-only.
When using `docker-compose.production.yml`, manage configuration on the host and
recreate the services instead of saving it from the Settings UI. See the
[English guide](docs/deployment/ADMIN_AND_SETTINGS_TROUBLESHOOTING_EN.md) or
[中文指南](docs/deployment/ADMIN_AND_SETTINGS_TROUBLESHOOTING_CN.md) for
legacy-image recovery and rootless/NFS notes.

### Option B: source checkout

```bash
git clone https://github.com/OpenByteInc/QuantDinger.git
cd QuantDinger
cp backend_api_python/env.example backend_api_python/.env
cp .env.example .env
```

Before the first start, replace the example values in both environment files:

| File | Required production values |
| --- | --- |
| `backend_api_python/.env` | `SECRET_KEY`, `CREDENTIAL_ENCRYPTION_KEY`, `ADMIN_USER`, `ADMIN_PASSWORD` |
| `.env` | `POSTGRES_PASSWORD`, `REDIS_PASSWORD`, `CELERY_REDIS_PASSWORD`, `GRAFANA_ADMIN_PASSWORD` |

Generate independent secrets with:

```bash
python -c "import secrets; print(secrets.token_hex(32))"
```

Start the core stack from local backend source:

```bash
docker compose up -d --build
docker compose ps
```

The base stack does not start Prometheus, Grafana, or Alertmanager. This keeps
the default open-source installation smaller.

For detailed installation paths, Windows notes, China mirror settings, and
PostgreSQL migration guidance, see
[Installation troubleshooting](docs/deployment/INSTALL_TROUBLESHOOTING.md) and the
[cloud deployment guide](docs/deployment/CLOUD_DEPLOYMENT_EN.md).

## Production deployment

Validate secrets before starting a production stack:

```bash
python backend_api_python/scripts/check_production_config.py \
  --env-file .env \
  --env-file backend_api_python/.env
```

Start the hardened runtime with optional observability:

```bash
docker compose \
  -f docker-compose.yml \
  -f docker-compose.production.yml \
  -f docker-compose.observability.yml \
  up -d --build
```

Omit `docker-compose.observability.yml` when the host is resource-constrained or
monitoring is provided externally.

Production rules:

- expose only a TLS reverse proxy on ports 80/443;
- keep PostgreSQL, both Redis instances, Prometheus, Grafana, and Alertmanager
  off the public internet;
- do not deploy with example passwords or empty encryption keys;
- back up PostgreSQL and the durable `redis-jobs` volume;
- keep cache Redis disposable and never use it as the Celery broker;
- review worker health and application readiness after every deployment.

The full checklist is in [Production hardening](docs/deployment/PRODUCTION_HARDENING.md).

## Local endpoints

All published ports bind to loopback by default.

| Service | Default URL | Purpose |
| --- | --- | --- |
| Web | <http://127.0.0.1:8888> | Desktop web client and same-origin API proxy. |
| Mobile H5 | <http://127.0.0.1:8889> | Mobile web client and same-origin API proxy. |
| Backend | <http://127.0.0.1:5000> | Direct API access and health endpoints. |
| Grafana | <http://127.0.0.1:3000> | Dashboards; available only with the observability overlay. |
| Prometheus | <http://127.0.0.1:9090> | Metrics storage and queries; optional. |
| Alertmanager | <http://127.0.0.1:9093> | Alert grouping, silencing, and delivery; optional. |

Container-only ports such as the job Redis and exporters are not published to
the host.

## Observability

The monitoring stack is optional by design:

- **Prometheus** collects API, worker, PostgreSQL, and Redis metrics.
- **Grafana** turns those metrics into operator dashboards.
- **Alertmanager** groups alerts, manages silences, and sends notifications once
  a receiver is configured.

Start it for local diagnostics without the production overlay:

```bash
docker compose \
  -f docker-compose.yml \
  -f docker-compose.observability.yml \
  up -d
```

Monitoring services stay on `127.0.0.1`. Use a VPN, SSH tunnel, or authenticated
reverse proxy for remote administration. See
[Observability](docs/deployment/OBSERVABILITY.md) for dashboards, alerts, retention, and
receiver configuration.

## Security model

- Broker credentials and MFA secrets are encrypted with a stable
  `CREDENTIAL_ENCRYPTION_KEY`.
- Agent tokens are hashed, scoped, rate-limited, and audit-logged.
- Agent trading is paper-only by default; live access requires both token and
  server-side authorization.
- Long-running strategy ownership uses leases, heartbeats, and fencing tokens.
- Production containers run without root privileges or Linux capabilities.
- Host port defaults are loopback-only; public access should terminate at a TLS
  reverse proxy.

Report vulnerabilities privately according to [SECURITY.md](SECURITY.md). Do
not include credentials, account data, or exploitable details in public issues.

## Strategy and integration surfaces

| Area | Current surface |
| --- | --- |
| Indicators | Python chart overlays, markers, bands, and signals. |
| Strategies | Strategy API V2 intents, sizing, risk, backtests, and live runtime. |
| Crypto | Binance, OKX, Bitget, Bybit, Gate, HTX, and adapter extensions. |
| Traditional brokers | IBKR and Alpaca workflows. |
| AI providers | OpenRouter, OpenAI-compatible APIs, Google, DeepSeek, Grok, MiniMax, and custom endpoints. |
| Automation | Human API, Agent Gateway, MCP server, Celery jobs, schedules, and notifications. |

Start with the [Indicator guide](docs/trading/INDICATOR_DEV_GUIDE.md),
[Strategy guide](docs/trading/STRATEGY_DEV_GUIDE.md), and
[Extension guide](docs/architecture/EXTENSION_GUIDE.md).

## AI agents and MCP

The Agent Gateway is exposed under `/api/agent/v1`. The included MCP server lets
clients such as Cursor, Claude Code, and Codex call approved tools without
receiving broker credentials or administrator JWTs.

Live trading through an agent requires all of the following:

1. a token with trading scope;
2. `paper_only=false` on that token;
3. `AGENT_LIVE_TRADING_ENABLED=true` on the server;
4. operator-configured limits and allowlists.

See [MCP setup](docs/agent/MCP_SETUP.md),
[Agent quick start](docs/agent/AGENT_QUICKSTART.md), and the
[Agent OpenAPI document](docs/agent/agent-openapi.json).

## Development

Backend development uses Python 3.12:

```bash
cd backend_api_python
python -m venv .venv
python -m pip install -r requirements-dev.txt
python -m pytest -m "not integration and not stress" --ignore=tests/release_gate -q
ruff check app scripts tests
```

Useful repository checks:

```bash
python scripts/check_version.py
python scripts/check_mojibake.py
docker compose -f docker-compose.yml config -q
docker compose -f docker-compose.yml -f docker-compose.production.yml -f docker-compose.observability.yml config -q
```

API changes should follow [API conventions](docs/architecture/API_CONVENTIONS.md), update the
OpenAPI artifact when required, and pass the compatibility workflow.

## Repository layout

This repository contains the backend, worker processes, deployment definitions,
operations configuration, documentation, and MCP server. The desktop and mobile
client source code live in separate repositories; this repository consumes their
published images in the Compose stacks.

```
/* Detailed source-code truncated for AI context efficiency. */
```

### Main execution paths

| Flow | Path through the repository |
| --- | --- |
| Synchronous API request | `app/routes` -> `app/services` -> database, cache, market-data, or trading adapter |
| Durable strategy command | API route -> PostgreSQL command record -> `trading-worker` -> strategy runtime and broker adapter |
| Finite background job | API or Celery beat -> job Redis -> `app/tasks` in `celery-worker` -> PostgreSQL result |
| Scheduled domain work | `app/commands/scheduler.py` -> scheduling services -> durable state and notifications |
| Monitoring | API and workers -> `app/observability` metrics -> Prometheus -> Grafana and Alertmanager |
| Agent or MCP call | MCP client -> `mcp_server` -> `/api/agent/v1` -> the same service layer used by human APIs |

Long-lived trading loops belong to the trading worker. Finite, retryable work
belongs to Celery. HTTP routes validate and delegate; they must not own trading
loops, exchange-specific behavior, or large database workflows.

### Where changes belong

| Change | Primary location | Usually update as well |
| --- | --- | --- |
| Add or modify an HTTP endpoint | `backend_api_python/app/routes/` | `app/openapi/`, route/contract tests, API docs |
| Add a business workflow | `backend_api_python/app/services/` | focused service tests |
| Add an exchange or broker integration | `app/services/live_trading/` or the broker package | credential policy, adapter tests, docs |
| Add a market-data source | `app/data_sources/` | provider aggregation, cache keys, tests |
| Add dashboard, news, or macro aggregation | `app/data_providers/` | route facade and cache policy |
| Add a finite asynchronous task | `app/tasks/` | `celery_app.py`, queue routing, task tests |
| Add long-lived process behavior | `app/workers/`, `app/commands/`, or `app/runtime/` | Compose command, health checks, ownership tests |
| Change the database schema | `backend_api_python/migrations/` | migration/release-gate tests and docs |
| Add metrics or alerts | `app/observability/` and `ops/` | dashboard, alert rule, observability docs |
| Add an MCP tool | `mcp_server/src/quantdinger_mcp/` | Agent Gateway scope, security tests, agent docs |

The web and mobile repositories publish their own GHCR images. Node.js is only
needed when building those clients from source. For deeper ownership rules, read
[Architecture](docs/architecture/ARCHITECTURE.md),
[Module boundaries](docs/architecture/MODULE_BOUNDARIES.md), and
[Process roles](docs/architecture/PROCESS_ROLES_AND_TASKS.md).

## Documentation

The maintained documentation index is available at [`docs/README.md`](docs/README.md).

| Topic | Document |
| --- | --- |
| Contributor architecture | [Architecture](docs/architecture/ARCHITECTURE.md) |
| Module ownership | [Module boundaries](docs/architecture/MODULE_BOUNDARIES.md) |
| Process and task ownership | [Process roles](docs/architecture/PROCESS_ROLES_AND_TASKS.md) |
| Production runtime | [Production hardening](docs/deployment/PRODUCTION_HARDENING.md) |
| Metrics and alerts | [Observability](docs/deployment/OBSERVABILITY.md) |
| Human API contracts | [API conventions](docs/architecture/API_CONVENTIONS.md) |
| OpenAPI artifacts | [API documentation](docs/api/README.md) |
| Strategy development | [Strategy guide](docs/trading/STRATEGY_DEV_GUIDE.md) |
| Indicator development | [Indicator guide](docs/trading/INDICATOR_DEV_GUIDE.md) |
| MCP and agents | [Agent documentation](docs/agent/README.md) |
| Cloud deployment | [Cloud deployment](docs/deployment/CLOUD_DEPLOYMENT_EN.md) |
| Installation problems | [Troubleshooting](docs/deployment/INSTALL_TROUBLESHOOTING.md) |

## Contributing

Read [CONTRIBUTING.md](CONTRIBUTING.md) and [DEVELOPMENT.md](DEVELOPMENT.md)
before opening a pull request. Keep routes thin, preserve API compatibility,
place long-running behavior in the correct process, and include focused tests
for high-risk changes.

## Exchange partner links

These are referral links. QuantDinger may receive a commission or trading-fee
rebate when a user registers through one of them. This does not add a separate
charge to the user; eligibility and terms are controlled by each venue and may
change. Always verify the destination domain before creating an account.

The same links are available in the application under **Profile → Open account**
and **Broker Accounts → Open account**.

| Exchange | Signup link |
| --- | --- |
| Binance | [Register](https://www.bsmkweb.cc/register?ref=QUANTDINGER) |
| Bitget | [Register](https://partner.hdmune.cn/bg/7r4xz8kd) |
| Bybit | [Register](https://partner.bybit.com/b/DINGER) |
| OKX | [Register](https://www.xqmnobxky.com/join/QUANTDINGER) |
| Gate.io | [Register](https://www.gateport.business/share/DINGER) |
| HTX | [Register](https://www.htx.com/invite/zh-cn/1f?invite_code=dinger) |

## License and commercial terms

- Backend source code is licensed under [Apache License 2.0](LICENSE).
- QuantDinger is a product of **Open Byte Inc**. The name, logo, product
  identity, and commercial licensing are managed separately from the code license.
- Web frontend source is published in
  [QuantDinger Frontend](https://github.com/OpenByteInc/QuantDinger-Vue) under
  its own source-available license.
- Mobile H5 and native client source is published in
  [QuantDinger Mobile](https://github.com/OpenByteInc/QuantDinger-Mobile) under
  its own source-available license.
- Trademark, branding, attribution, and watermark use is governed by
  [TRADEMARKS.md](TRADEMARKS.md). Apache 2.0 does not grant trademark rights.

For commercial licensing, frontend source access, branding authorization, or
deployment support:

- Website: [quantdinger.com](https://www.quantdinger.com)
- Telegram: [t.me/worldinbroker](https://t.me/worldinbroker)
- Email: [support@quantdinger.com](mailto:support@quantdinger.com)

## Legal notice and compliance

QuantDinger is intended for **lawful research, education, and compliant trading
only**. It must not be used for fraud, market manipulation, sanctions evasion,
money laundering, or other illegal activity. Operators are responsible for
following the laws, licensing requirements, tax rules, broker or exchange terms,
and data regulations that apply in every jurisdiction where they deploy or use
the software.

**This project does not provide legal, tax, investment, financial, or regulatory
advice.** Trading, including automated and leveraged trading, can result in the
loss of some or all capital. Historical data, backtests, simulated results, AI
output, indicators, and strategy examples do not guarantee future performance.
Users must independently review strategies, permissions, order limits, and risk
controls before enabling live execution.

The software is provided under the terms of the applicable license and is used
at the operator's own risk. To the extent permitted by law, project maintainers
and contributors disclaim liability for trading losses, data loss, service
interruption, third-party failures, security incidents, or regulatory consequences
arising from use or misuse of the software.

## Community and support


  [](https://t.me/quantdinger)
  [](https://discord.com/invite/tyx5B6TChr)
  [](https://youtube.com/@quantdinger)
  [](https://x.com/QuantDinger_EN)


- [Website](https://www.quantdinger.com)
- [Contributing guide](CONTRIBUTING.md)
- [Contributors](CONTRIBUTORS.md)
- [Report bugs or request features](https://github.com/OpenByteInc/QuantDinger/issues)
- Email: [support@quantdinger.com](mailto:support@quantdinger.com)

## Sponsors

QuantDinger's continued development and open-source community are supported by:



| **Atlas Cloud**
      
      AI inference sponsor | **Amazon Web Services**
      
      Cloud infrastructure sponsor |
| --- | --- |



We are grateful to [Atlas Cloud](https://www.atlascloud.ai/?utm_source=github&utm_medium=link&utm_campaign=quantdinger) for supporting AI
model inference and to [Amazon Web Services](https://aws.amazon.com/) for
supporting the cloud infrastructure that helps QuantDinger serve its community.

## Support the project

If QuantDinger is useful to you, a GitHub star, contribution, or donation helps
fund ongoing development and infrastructure.

Crypto donation address:

```text
0x96fa4962181bea077f8c7240efe46afbe73641a7
```

Crypto transfers are irreversible. Confirm the address and intended network with
the project maintainers before sending funds.

## Acknowledgements

QuantDinger stands on top of a strong open-source ecosystem. Special thanks to
the maintainers and contributors of projects including:

- [Flask](https://flask.palletsprojects.com/)
- [Gunicorn](https://gunicorn.org/)
- [Celery](https://docs.celeryq.dev/)
- [PostgreSQL](https://www.postgresql.org/)
- [Redis](https://redis.io/)
- [Pandas](https://pandas.pydata.org/)
- [NumPy](https://numpy.org/)
- [CCXT](https://github.com/ccxt/ccxt)
- [yfinance](https://github.com/ranaroussi/yfinance)
- [AkShare](https://github.com/akfamily/akshare)
- [Vue.js](https://vuejs.org/)
- [Ant Design Vue](https://antdv.com/)
- [KLineCharts](https://github.com/klinecharts/KLineChart)
- [ECharts](https://echarts.apache.org/)
- [Capacitor](https://capacitorjs.com/)
- [bip-utils](https://github.com/ebellocchia/bip_utils)
- [Prometheus](https://prometheus.io/)
- [Grafana](https://grafana.com/)

## P.S. — A note on the name

**QuantDinger** is a small tribute to
**[Erwin Schrödinger](https://en.wikipedia.org/wiki/Erwin_Schr%C3%B6dinger)** —
the “-dinger” in our name is the tail of “Schrödinger”. The cat in the box was a
thought experiment; every un-fired strategy is its own little version of it —
simultaneously winning and losing until the order actually fills. Backtests open
the box. Live trading collapses the wavefunction. Trade carefully.

---

## File: backend_api_python/app/services/alpaca_trading/README.md

# Alpaca Trading Module

Trade US stocks, ETFs, and crypto via [Alpaca Markets](https://alpaca.markets) REST API.
Mirrors `ibkr_trading/` module structure for consistency.

## Why Alpaca?

- **Zero commission** on stocks/ETFs/crypto (vs IBKR's per-share or tiered fees)
- **No TWS/Gateway required** — pure stateless REST authentication
- **Paper trading built-in** — separate paper-api.alpaca.markets endpoint
- **Modern Python SDK** — `alpaca-py` is well-maintained, async-friendly
- **Crypto support** — same client handles stocks AND crypto (BTC/USD, ETH/USD, etc.)
- **Fractional shares** — buy $5 worth of TSLA without owning a full share

## Installation

```bash
pip install alpaca-py
```

## Configuration

Add to `backend_api_python/.env`:

```bash
# Paper trading (recommended for development)
ALPACA_API_KEY=PK********************
ALPACA_SECRET_KEY=********************
ALPACA_PAPER=true

# Live trading (only after thorough paper testing)
# ALPACA_API_KEY=AK********************  # Note: AK prefix = live
# ALPACA_SECRET_KEY=********************
# ALPACA_PAPER=false
```

**Key prefix tells you what mode you're in:**
- `PK*` = paper account (paper-api.alpaca.markets, no real money)
- `AK*` = live account (api.alpaca.markets, real money)

Get your keys at:
- Paper: https://app.alpaca.markets/paper/dashboard/overview → "Generate New Key"
- Live: https://app.alpaca.markets/brokerage/dashboard/overview → "Generate New Key"

## Basic usage

```python
from app.services.alpaca_trading import AlpacaClient, AlpacaConfig

config = AlpacaConfig(
    api_key="PK********************",
    secret_key="********************",
    paper=True,  # paper trading
)
client = AlpacaClient(config)
client.connect()  # Verifies credentials via /account endpoint

# Account snapshot
acct = client.get_account_summary()
print(f"Buying power: ${acct['summary']['BuyingPower']['value']}")

# Place a market BUY of 1 share of SPY
result = client.place_market_order(symbol="SPY", side="buy", quantity=1)
print(f"Order {result.order_id}: filled={result.filled} @ ${result.avg_price}")

# Get current positions
for pos in client.get_positions():
    print(f"{pos['symbol']}: {pos['quantity']} @ ${pos['avgCost']}, unrealized=${pos['unrealizedPnL']:+.2f}")

# Cancel any open order
client.cancel_order(order_id="...")

client.disconnect()
```

## Crypto trading

Alpaca supports crypto using the same client — just pass `market_type="crypto"`:

```python
result = client.place_market_order(
    symbol="BTC/USD",  # or "BTCUSD" — auto-normalized
    side="buy",
    quantity=0.01,
    market_type="crypto",
)
```

Note: crypto orders use `time_in_force=GTC` (good-till-cancelled) since the market is 24/7;
stock orders default to `time_in_force=DAY`.

## Extended-hours trading

For limit orders on US equities, you can trade in pre-market (4:00-9:30 ET) or
after-hours (16:00-20:00 ET):

```python
result = client.place_limit_order(
    symbol="SPY",
    side="buy",
    quantity=1,
    price=740.00,
    extended_hours=True,  # Enables pre/post-market trading
)
```

## API endpoints (when registered as Flask blueprint)

All endpoints require `@login_required`:

| Method | Path | Purpose |
|--------|------|---------|
| GET | `/api/alpaca/status` | Connection state |
| POST | `/api/alpaca/connect` | Connect with API key/secret |
| POST | `/api/alpaca/disconnect` | Clear local state |
| GET | `/api/alpaca/account` | Account summary (buying power, equity, etc.) |
| GET | `/api/alpaca/positions` | Current positions |
| GET | `/api/alpaca/orders` | Open orders |
| POST | `/api/alpaca/order` | Place market or limit order |
| DELETE | `/api/alpaca/order/` | Cancel order |
| GET | `/api/alpaca/quote/<symbol>?marketType=USStock` | Latest bid/ask |

## Differences from IBKR module

| Feature | IBKR | Alpaca |
|---------|------|--------|
| Auth | TWS/Gateway socket (host/port/clientId) | REST API key+secret |
| Order IDs | Integer | UUID string |
| Connection | Stateful, persistent socket | Stateless REST |
| Paper mode (IBKR TWS/Gateway) | Port 7497/4002 | Different base URL |
| Symbol format | `AAPL` (stocks), `0700.HK` (HK) | `AAPL` (US), `BRK.B` (US class), `BTC/USD` (crypto) |
| Extended hours | Configurable per-order | Configurable per-order (limit only) |
| Crypto | No (separate IBKR Crypto product) | Yes, same client |

## Troubleshooting: WebSocket `400 invalid syntax`

QuantDinger **connection test** and live orders use the **REST Trading API** (`TradingClient.get_account()`), **not** the market-data WebSocket at `wss://stream.data.alpaca.markets/...`.

If you see Alpaca error **code 400 / invalid syntax** from the [streaming docs](https://docs.alpaca.markets/us/docs/streaming-market-data#authentication), that is almost always from a **WebSocket client** (custom script, another app, or a chart feed), not from `/api/alpaca/connect` or `/strategies/test-connection`.

Common causes:

| Issue | Fix |
|-------|-----|
| Subscribe before auth | After `connected`, send `{"action":"auth","key":"...","secret":"..."}` within 10s |
| Wrong JSON shape | Use `action` + channel keys, e.g. `{"action":"subscribe","trades":["AAPL"]}` |
| Invalid symbol | US stocks: `AAPL` (no `BTC/USDT`). Crypto: `BTC/USD` (Alpaca does **not** use `BTC/USDT`) |
| Class shares | `BRK/B` → `BRK.B` for REST; do not treat as a crypto pair |

This module normalizes symbols (`symbols.py`): `BTC/USDT` → `BTC/USD` for crypto, `BRK/B` → `BRK.B` for equities.

## Limitations / TODO

- [ ] No bracket orders yet (Alpaca supports them; not yet wrapped)
- [ ] No stop or stop-limit orders yet (alpaca-py supports `StopOrderRequest`, `StopLimitOrderRequest`)
- [ ] No historical bar fetching helpers (use `StockHistoricalDataClient.get_stock_bars()` directly)
- [ ] No WebSocket streaming (alpaca-py supports it; not yet wired)
- [ ] No options trading (Alpaca recently added; not implemented)

## Reference

- alpaca-py docs: https://alpaca.markets/sdks/python
- Alpaca API reference: https://docs.alpaca.markets/reference

---

## File: backend_api_python/app/services/ibkr_trading/README.md

# Interactive Brokers Trading Module

Supports US stocks trading via TWS or IB Gateway.

## Installation

```bash
pip install ib_insync
```

Or the dependency is already in `requirements.txt`.

## Port Reference

| Client | Live Port | Paper Port |
|--------|-----------|------------|
| TWS    | 7496      | 7497       |
| IB Gateway | 4001  | 4002       |

## TWS / IB Gateway Configuration

1. Open TWS or IB Gateway
2. Go to **Configure** -> **API** -> **Settings**
3. Enable the following options:
   - ✅ Enable ActiveX and Socket Clients
   - ✅ Allow connections from localhost only
4. Set Socket port (refer to the table above)
5. Click Apply / OK

### Client ID (important)

Interactive Brokers allows **one API connection per `clientId`**. If two programs use the same id, **the newer connection replaces the older** — often within a few seconds it looks like a random disconnect, and live orders then fail with “Failed to connect”.

- `POST /api/ibkr/connect` (admin UI test) defaults to **clientId=1**.
- Strategy / live-order clients use **`ibkr_client_id` from credentials** (default **7** when omitted) or env **`IBKR_ORDER_CLIENT_ID`** (default `7`).

Keep manual testing on **1** and automation on **7** (or any other unused id). If you still see drops on Windows, ensure `ib_insync` runs with asyncio patched (QuantDinger calls `util.patchAsyncio()` at app startup).

## API Endpoints

### Connection Management

```
GET  /api/ibkr/status          # Get connection status
POST /api/ibkr/connect         # Connect to TWS/Gateway
POST /api/ibkr/disconnect      # Disconnect
```

### Account Queries

```
GET  /api/ibkr/account         # Account information
GET  /api/ibkr/positions       # Current positions
GET  /api/ibkr/orders          # Open orders
```

### Trading

```
POST   /api/ibkr/order         # Place order
DELETE /api/ibkr/order/    # Cancel order
```

### Market Data

```
GET  /api/ibkr/quote?symbol=AAPL&marketType=USStock
```

## Usage Examples

### Connect

```bash
curl -X POST http://localhost:5000/api/ibkr/connect \
  -H "Content-Type: application/json" \
  -d '{"host": "127.0.0.1", "port": 7497, "clientId": 1}'  # TWS Paper default
```

### Place Order

```bash
# Market order: buy 10 shares of AAPL
curl -X POST http://localhost:5000/api/ibkr/order \
  -H "Content-Type: application/json" \
  -d '{"symbol": "AAPL", "side": "buy", "quantity": 10, "marketType": "USStock"}'

# Limit order: sell 100 shares of MSFT
curl -X POST http://localhost:5000/api/ibkr/order \
  -H "Content-Type: application/json" \
  -d '{"symbol": "MSFT", "side": "sell", "quantity": 100, "marketType": "USStock", "orderType": "limit", "price": 400}'
```

### Get Positions

```bash
curl http://localhost:5000/api/ibkr/positions
```

## Symbol Format

| Market | Format | Examples |
|--------|--------|----------|
| US Stock | Ticker symbol | `AAPL`, `TSLA`, `GOOGL` |

## Important Notes

1. **TWS/Gateway must be running**: Ensure TWS or IB Gateway is started and logged in before using the API
2. **Market data subscription**: Real-time quotes may require market data subscription
3. **Client ID**: Use different clientId if multiple programs connect to the same TWS/Gateway
4. **Readonly mode**: Set `readonly: true` to only query without trading
5. **Multi-account**: Specify `account` parameter if you have multiple sub-accounts

## Troubleshooting

| Error | Cause | Solution |
|-------|-------|----------|
| Connection failed | TWS/Gateway not running | Start and login to TWS/Gateway |
| Connection failed | Wrong port | Check API port setting in TWS/Gateway |
| Connection failed | API not enabled | Enable Socket API in TWS/Gateway settings |
| Client ID conflict | Same clientId already connected | Use a different clientId |
| Invalid contract | Wrong symbol format | Check symbol format |

## Removing This Module

To remove this module, delete the following files/directories:

```
backend_api_python/app/services/ibkr_trading/    # Entire directory
backend_api_python/app/routes/ibkr.py            # Route file
```

Then remove the related import and registration code in `app/routes/__init__.py`.

## Docker Note

When running in Docker, IBKR trading requires TWS/IB Gateway to be accessible from the container. 
For local deployment, you can:

1. Run TWS/Gateway on host machine
2. Use host network mode or configure port mapping
3. Set `host` to the host machine's IP address (e.g., `host.docker.internal` on Docker Desktop)

> **Note**: IBKR connection parameters are configured per-strategy in the frontend, not via environment variables.

---

## File: backend_api_python/README.md

# QuantDinger Python Backend

This directory contains the Flask API, domain services, background workers,
database migrations, OpenAPI integration, and backend tests for QuantDinger.

Start with the [project README](../README.md) for product installation. This
document is the backend contributor and operator quick reference.

## Runtime model

The production deployment reuses one backend image across independent process
roles:

| Role | Command | Ownership |
| --- | --- | --- |
| API | `gunicorn -c gunicorn_config.py run:app` | HTTP, authentication, validation, and durable command submission. |
| Migration | `python -m app.commands.migrate` | Fail-fast schema application before services start. |
| Trading | `python -m app.commands.trading_worker` | Strategy runtimes, pending orders, broker sessions, and reconciliation. |
| Scheduler | `python -m app.commands.scheduler` | Portfolio, deployment, payment, and signal schedules. |
| Celery worker | `celery -A app.celery_app:celery_app worker` | Finite AI, backtest, experiment, report, and maintenance jobs. |
| Celery beat | `celery -A app.celery_app:celery_app beat` | Periodic task dispatch. |

HTTP processes must not start trading or scheduler threads. Celery must not own
long-lived strategy loops or broker sessions. See
[Process roles and durable tasks](../docs/architecture/PROCESS_ROLES_AND_TASKS.md).

## Storage model

- PostgreSQL 18 is the system of record.
- `redis` is an evictable application cache.
- `redis-jobs` is the durable Celery broker/result tier with AOF and
  `noeviction`.
- Strategy ownership uses PostgreSQL commands, leases, fencing tokens, and
  worker heartbeats.

Queue state must never share the cache Redis eviction policy.

## Directory map

```text
app/
  commands/             Process entry points and operational commands
  config/               Environment-backed configuration
  data_providers/       Aggregated market and global data providers
  data_sources/         Raw market data adapters
  observability/        Metrics and request instrumentation
  openapi/              Human API schemas, registration, and export metadata
  routes/               HTTP facades and compatibility routes
  services/             Domain workflows and integration orchestration
  tasks/                Celery task definitions
  utils/                Small infrastructure helpers
migrations/             PostgreSQL schema and incremental migrations
scripts/                Backend quality, export, and production checks
tests/                  Unit, integration, contract, and release-gate tests
```

Read [Backend architecture](../docs/architecture/ARCHITECTURE.md) and
[Module boundaries](../docs/architecture/MODULE_BOUNDARIES.md) before larger changes.

## Configuration

Create the runtime environment file:

```bash
cp env.example .env
```

At minimum, replace these values before a shared or production deployment:

```dotenv
SECRET_KEY=
CREDENTIAL_ENCRYPTION_KEY=
ADMIN_USER=
ADMIN_PASSWORD=
```

Generate each secret independently:

```bash
python -c "import secrets; print(secrets.token_hex(32))"
```

Docker-level database, Redis, Grafana, port, image, and resource settings belong
in the repository-root `.env`; application runtime settings belong here.

## Docker workflow

Run these commands from the repository root.

Core development stack:

```bash
docker compose up -d --build
docker compose ps
```

Production-hardened stack with optional monitoring:

```bash
python backend_api_python/scripts/check_production_config.py \
  --env-file .env \
  --env-file backend_api_python/.env

docker compose \
  -f docker-compose.yml \
  -f docker-compose.production.yml \
  -f docker-compose.observability.yml \
  up -d --build
```

The production overlay uses UID/GID `10001`, a read-only root filesystem,
dropped capabilities, bounded temporary filesystems, and CPU/memory limits.
Remove the observability overlay when monitoring is provided elsewhere.

## Local Python workflow

Prerequisites:

- Python 3.12;
- PostgreSQL 18;
- Redis 8 for cache and Celery-backed workflows.

Create an environment and install development dependencies:

```bash
python -m venv .venv
python -m pip install --upgrade pip
python -m pip install -r requirements.lock -r requirements-dev.txt
```

Apply migrations:

```bash
QD_PROCESS_ROLE=migration python -m app.commands.migrate
```

Windows PowerShell equivalent:

```powershell
$env:QD_PROCESS_ROLE = "migration"
python -m app.commands.migrate
```

Start the API for local debugging:

```bash
python run.py
```

Use the Docker process model when testing trading, scheduler, or Celery ownership
boundaries. A single local API process is not a substitute for production role
separation.

## Health and operations

| Endpoint | Purpose |
| --- | --- |
| `GET /` | Application identity and resolved version. |
| `GET /api/health` | Basic liveness. |
| `GET /api/health/ready` | PostgreSQL and Celery broker readiness. |
| `GET /api/health/workers` | Trading, scheduler, and Celery heartbeat summary. |
| `GET /metrics` | Prometheus metrics. Keep this private. |

Container logs default to structured JSON and include process role and request
ID. The optional monitoring stack is documented in
[Observability](../docs/deployment/OBSERVABILITY.md).

## API contracts

Human API routes use the existing `/api/...` surface. AI agents use the scoped
`/api/agent/v1/...` gateway with a separate contract.

- Human API conventions: [API_CONVENTIONS.md](../docs/architecture/API_CONVENTIONS.md)
- Committed OpenAPI: [openapi.yaml](../docs/api/openapi.yaml)
- Agent contract: [agent-openapi.json](../docs/agent/agent-openapi.json)

Regenerate the human API artifact after schema or route metadata changes:

```bash
python scripts/export_openapi.py
```

With `OPENAPI_ENABLED=true`, interactive documentation is available at:

- Swagger UI: <http://127.0.0.1:5000/api/docs/swagger>
- ReDoc: <http://127.0.0.1:5000/api/docs/redoc>

## Quality checks

Run the normal backend suite:

```bash
python -m compileall -q app scripts tests
ruff check app scripts tests
python scripts/backend_quality_check.py
python scripts/check_requirements_lock.py
python -m pytest -m "not integration and not stress" --ignore=tests/release_gate -q
```

Run release gates independently:

```bash
python -m pytest tests/release_gate/test_cta_backtest_release_gate.py -q
python -m pytest tests/release_gate/test_live_execution_release_gate.py -q
python -m pytest tests/release_gate/test_robot_strategy_unification.py -q
```

Security CI additionally runs `pip-audit`, Bandit, Gitleaks, and CodeQL.

## Contributor rules

- Keep routes focused on parsing, authentication, service calls, and response
  mapping.
- Keep Flask request objects out of domain services.
- Put exchange-specific normalization and errors near the adapter.
- Make state mutations idempotent and define their retry behavior.
- Keep code comments, docstrings, logs, and internal errors in English.
- Preserve existing paths and response fields unless an intentional contract
  change is documented and tested.
- Add finite retryable work to Celery; keep long-lived ownership in the trading
  or scheduler process.

## Versioning

The local fallback version is read from [`VERSION`](VERSION). Release builds can
inject `APP_VERSION` from a Git tag. Both `v5.0.1` and `5.0.1` normalize to the
API display value `5.0.1`.

Update checked-in version declarations from the repository root:

```bash
python scripts/bump_version.py 5.0.1
python scripts/check_version.py
```

## License

Apache License 2.0. See the repository-root [LICENSE](../LICENSE).

---

## File: docs/api/README.md

# QuantDinger Web API (OpenAPI)

Human-facing REST API specification generated from **flask-smorest** (`app/openapi/`).

| File | Purpose |
|------|---------|
| [`openapi.yaml`](openapi.yaml) | Committed SSOT — update via `backend_api_python/scripts/export_openapi.py` |
| [`index.html`](index.html) | Static Redoc viewer — **must be served over HTTP** (see below) |

## View docs locally

ReDoc cannot load `openapi.yaml` when you double-click `index.html` (`file://` is blocked by browser same-origin policy). Use any static server from the repo root or this folder:

```bash
# Python (from docs/api/)
python -m http.server 8080
# open http://localhost:8080/index.html

# or from repo root
cd docs/api && npx --yes serve -p 8080
```

If you see `process is not defined`, refresh after pulling the latest `index.html` (includes a browser shim + pinned ReDoc 2.4.0).

## Conventions

See [`../architecture/API_CONVENTIONS.md`](../architecture/API_CONVENTIONS.md) for envelopes, auth, and Public/Internal tiers.

## Agent API

AI agents use a separate contract: [`../agent/agent-openapi.json`](../agent/agent-openapi.json).

## Regenerate

```bash
cd backend_api_python
pip install -r requirements.txt
python scripts/export_openapi.py
```

## Local interactive docs

With the backend running in debug mode (or `OPENAPI_ENABLED=true`):

- Swagger UI: http://localhost:5000/api/docs/swagger
- ReDoc: http://localhost:5000/api/docs/redoc

---

## File: docs/agent/AGENT_ENVIRONMENT_DESIGN.md

# QuantDinger — Multi-Agent Runtime Environments (Design)

| Item | Value |
|------|--------|
| Status | Draft (for review and phased rollout) |
| Audience | Maintainers and developers using Cursor, Claude Code, Codex, or similar coding agents |
| Repository | [QuantDinger](https://github.com/OpenByteInc/QuantDinger) — self-hosted quant stack: research, strategies, backtests, live trading |

---

## 1. Background and goals

### 1.1 Background

When multiple coding agents and IDE assistants (Cursor, Claude Code, OpenAI Codex, CLI/sandbox bots) work in the same repository without shared conventions, teams often see:

- Agents re-reading a very long README, wasting context and misreading intent;
- Guessed HTTP paths and payloads that do not match the backend;
- Accidental touches to secrets, production databases, or money-adjacent paths;
- Per-tool documentation that drifts from the repo.

### 1.2 Goals

Without locking into a single vendor, make this repository **stable and predictable** for many agent environments:

1. **Code collaboration** — When changing strategies, fixing bugs, or adding APIs, agents can quickly find directories and verification commands.
2. **Capability discovery** — Humans and machines can learn what is allowed, what is forbidden, and how to validate changes.
3. **Optional extensions** — MCP, OpenAPI, and similar layers can be added later without replacing this structure.

### 1.3 Non-goals (explicit for this phase)

- Not every agent product must support MCP.
- No real secrets, internal-only URLs, or production credentials in design docs.
- No promise of **fully unattended live trading** in v1; live and capital flows stay behind human review and explicit strategy boundaries.

---

## 2. Design principles

| Principle | Meaning |
|-----------|---------|
| **Single source of truth (SSOT)** | “How to work in this repo” for agents lives in one primary doc (see §8); the root README only indexes it briefly. |
| **Layered contracts** | Documentation (intent) → commands (local) → API / MCP (product capabilities). Upper layers may depend on lower ones; do not mix layers in one blob. |
| **Minimal context pack** | Token-limited environments get a short, linkable doc (quick path) instead of irrelevant full-tree context. |
| **Secure by default** | Secrets, `.env`, production writes, and undocumented order APIs are **not** encouraged for autonomous agents; red lines must be explicit in Layer 1. |
| **Decoupled from implementation** | This design states **what should exist**; filenames (e.g. `AGENTS.md`) may change at rollout time while semantics stay the same. |

---

## 3. Architecture — three layers

```
┌─────────────────────────────────────────────────────────────┐
│  Layer 1 — Documentation contract (humans + agents)         │
│  Repo map, red lines, recommended workflow, pointers to 2/3 │
└───────────────────────────┬─────────────────────────────────┘
                            │
┌───────────────────────────▼─────────────────────────────────┐
│  Layer 2 — Command contract (terminal / CI / CLI agents)    │
│  Stable scripts or Make: install, lint, test, docker compose │
└───────────────────────────┬─────────────────────────────────┘
                            │
┌───────────────────────────▼─────────────────────────────────┐
│  Layer 3 — Machine interfaces (HTTP / MCP, optional)        │
│  OpenAPI or equivalent schema; optional MCP tools (narrow)   │
└─────────────────────────────────────────────────────────────┘
```

### 3.1 Layer 1 — Documentation contract

**Role:** Any agent that can read repo text knows **where to start and how to self-check** without calling the network.

Suggested structure (may be split across files; one index is mandatory):

- Top-level directory roles (`backend_api_python/`, `frontend/`, `docs/`, `scripts/`).
- Indicator and strategy entry points (link to `docs/trading/INDICATOR_DEV_GUIDE.md` and `docs/trading/STRATEGY_DEV_GUIDE.md` — avoid duplicating long excerpts).
- **Red lines** — Never commit `.env`; never put secrets in docs or examples; money/live changes require human review.
- **Happy path** — e.g. “Python-only strategy change → how to bring up Docker → how to run backend tests” in 3–5 steps.

**Relationship to the root README** — README keeps user-facing install and product story; add a short “For coding agents” pointer to `docs/agent/`.

### 3.2 Layer 2 — Command contract

**Role:** Every action that should reproduce locally or in CI is exposed as a **small set of stable commands**, not ad-hoc shell one-liners.

Implementation choices (Make, `npm` scripts, `invoke`, etc.) are up to maintainers:

| Category | Example intent (names may vary) |
|----------|----------------------------------|
| Environment | Copy env template, generate secrets (aligned with `env.example`, `scripts/`) |
| Run | Documented equivalent of `docker compose up` / build |
| Quality | lint, format, typecheck (if adopted) |
| Tests | Backend unit/integration entrypoints matching the repo’s stack |

**Constraint:** One official entry per goal; if two spellings exist (`docker-compose` vs `docker compose`), document the recommended one and compatibility notes.

### 3.3 Layer 3 — Machine interfaces (optional evolution)

**Role:** When an agent or external tool must **drive product behavior** (health, listings, backtests), it must not rely on guessing HTTP.

- **HTTP + OpenAPI (or equivalent)** — Machine-consumable contract for REST; update the contract when routes change.
- **MCP (Model Context Protocol)** — Expose **narrow, auditable** operations as tools (e.g. read-only health, read-only strategy list). Write and trading tools need separate review and allowlists.

**Principle:** Layer 3 is additive; agents without MCP should still complete most code tasks via Layers 1 + 2.

---

## 4. Mapping to agent environments

Product names evolve; map by **capability**, not brand-only details.

| Environment | Primary layers | Notes |
|-------------|----------------|-------|
| **Cursor** | Layer 1 + optional `.cursor/rules`; optional MCP | Rules: permanent red lines and repo terminology; MCP aligns with Layer 3. |
| **Claude Code** | Layer 1 + Layer 2 | Heavy use of terminal and in-repo docs; Bash/PowerShell must be explicit. |
| **OpenAI Codex (CLI/IDE)** | Layer 1 + Layer 2 | Similar to Claude Code; avoid vendor-only config as the sole source of truth. |
| **Lightweight CLI / sandbox bots** | Minimal context pack in Layer 1 + Layer 2 | Mount one short file or system prompt instead of the whole tree. |
| **Vendor-hosted agents** | Layer 1 index + HTTP (Layer 3) | If only APIs are visible, OpenAPI and auth docs are critical. |

**Note:** For specific products (e.g. OpenClaw, NanoBot), add one appendix row at rollout: **product → config / protocol → which layer(s)**. No separate architecture fork.

---

## 5. Security and compliance boundaries

### 5.1 Data and secrets

- Keys, API tokens, and DB passwords come only from environment variables or local `.env` (and `.env` is gitignored).
- Design docs, agent rules, and `AGENTS.md`-style files must **not** contain real secrets or production connection strings; use placeholders in examples.

### 5.2 Capital and live trading

- Order placement, transfers, and exchange credential changes are **not** in unattended agent flows by default.
- If a subset is ever exposed via MCP, require auth, audit logs, rate limits, human toggles, and document in Layer 1.

### 5.3 Strategy code and multi-tenancy

- For multi-user deployments, distinguish **platform core** paths from **user strategy / plugin** paths so agents do not rewrite shared security logic.

---

## 6. Repository anchors (facts)

Keep implementation aligned with the current tree (update this section if layout changes):

| Area | Typical path | Agent focus |
|------|--------------|-------------|
| Backend API | `backend_api_python/` | Routes, services, `env.example` |
| Frontend | `frontend/` (includes prebuilt `dist`) | Matches README “Node optional” story |
| Ops / one-command stack | `docker-compose.yml`, `scripts/` | Layer 2 commands should mirror this |
| Indicator / strategy guides | `docs/trading/INDICATOR_DEV_GUIDE.md`, `docs/trading/STRATEGY_DEV_GUIDE.md`, localized variants | Layer 1 links; do not duplicate long guides |

---

## 7. Phased roadmap (suggested)

| Phase | Deliverable | Value |
|-------|-------------|--------|
| **P0** | `docs/agent/` index + one-line README link; red lines and repo map | One SSOT for all agents |
| **P1** | 3–5 official commands (scripts or Make) listed in docs | Fewer broken ad-hoc shells |
| **P2** | Exported or hand-maintained OpenAPI for the backend | Reliable integrations and codegen |
| **P3** | Optional MCP server (read-only first, then expand) | Deeper Cursor / Claude-style tooling |

Phases are independently reviewable; **P0 does not depend on P2/P3**.

---

## 8. Document and file checklist (for implementation)

- [x] `docs/agent/AGENT_ENVIRONMENT_DESIGN.md` — this design (English SSOT).
- [x] `.cursor/skills/quantdinger-agent-workflow/` — project Cursor skill (English) pointing agents here.
- [x] `docs/agent/README.md` — short Layer 1 index for `docs/agent/`.
- [ ] Root `README.md` — dedicated “For coding agents” subsection pointing to the index above.
- [ ] (Optional) Root `AGENTS.md` — industry-style filename; may forward to `docs/agent/`.
- [ ] (Optional) `.cursor/rules/` — repo-specific terms and red lines only; avoid duplicating Layer 1 at length.
- [ ] Layer 2 — `scripts/agent-*.sh` or Makefile targets (names TBD at implementation).
- [ ] Layer 2 — Windows PowerShell + Bash notes (consistent with root README).
- [ ] P2/P3 — OpenAPI location, MCP package location (separate ADR acceptable).

---

## 9. Open questions (for review)

1. **OpenAPI source** — Generate static JSON from Flask at runtime, or generate in CI and commit? Tradeoff: drift vs build deps.
2. **MCP packaging** — Monorepo next to the API vs small standalone repo for MCP-only installs?

**Resolved:** Agent-facing documentation and project `.cursor/skills/` are **English only**; human product docs may remain multilingual elsewhere in `docs/`.

---

## 10. Revision history

| Version | Date | Notes |
|---------|------|--------|
| 0.1 | 2026-05-02 | First draft: three layers, security, roadmap, checklist |
| 0.2 | 2026-05-02 | Language policy: agent design and project skills are English-only; consolidated from former CN draft |

---

## File: docs/agent/AGENT_QUICKSTART.md

# Agent Gateway Quickstart

QuantDinger exposes a tenant-scoped Agent Gateway at `/api/agent/v1`. Agent tokens are separate from human JWT sessions and enforce capability scopes, market/instrument allowlists, rate limits, expiry, and paper-only restrictions.

The machine-readable contract is [agent-openapi.json](agent-openapi.json). MCP setup is documented in [MCP_SETUP.md](MCP_SETUP.md).

## Authenticate

Create an Agent Token from the human admin UI, store the full token when it is shown once, and send it as a bearer token:

```bash
curl -H "Authorization: Bearer $QUANTDINGER_AGENT_TOKEN" \
  http://localhost:8888/api/agent/v1/whoami
```

Scopes are `R` for reads, `W` for saved artifacts and deployment configuration, `B` for backtests, `N` for notification side effects, and `T` for runtime or order mutations. `C` is admin-only. Token permissions never bypass server-side live-trading controls.

Every mutating W/B/N/T request requires a unique `Idempotency-Key` header. Reuse the same key only when retrying the exact same method, route, query, and body. The gateway atomically reserves the key, returns a stored completed response on replay, and rejects concurrent or mismatched reuse.

## Strategy API V2

Executable strategies use Strategy API V2. Code defines `initialize(context)`, declares its universe and subscriptions, and provides `handle_data`, `on_rebalance`, or a scheduled callback. Markets, instruments, frequencies, dependencies, warmup, and leverage policy come from the compiled manifest.

The Agent Gateway exposes the complete source lifecycle:

1. List starter code with `GET /strategy-sources/templates`.
2. Compile code with `POST /strategy-sources/compile`.
3. Save a private source with `POST /strategy-sources`.
4. Inspect or update it through `/strategy-sources/{source_id}`.
5. Review immutable snapshots through `/strategy-sources/{source_id}/versions`.
6. Create a stopped deployment from the saved source id.

Source restoration requires an explicit `confirm=true` request and creates another immutable snapshot.

Create a stopped deployment from a saved source:

```bash
curl -X POST http://localhost:8888/api/agent/v1/strategies \
  -H "Authorization: Bearer $QUANTDINGER_AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: deploy-spy-trend-v1" \
  -d '{
    "name": "spy-trend",
    "sourceId": 12,
    "initialCapital": 10000,
    "executionMode": "signal",
    "leverageEnabled": false,
    "params": {"lookback": 50}
  }'
```

Update the same canonical fields with `PATCH /api/agent/v1/strategies/{id}`. Starting a deployment is intentionally not part of the W-scope configuration endpoint. A T-scope token can stop a running deployment through `/strategies/{id}/stop`.

## Backtests

Backtests accept Strategy API V2 code and run asynchronously:

```bash
curl -X POST http://localhost:8888/api/agent/v1/backtest/run \
  -H "Authorization: Bearer $QUANTDINGER_AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: spy-trend-2025" \
  -d '{
    "code": "def initialize(context):\n    g.symbol = \"USStock:SPY\"\n    context.set_universe([g.symbol])\n    context.subscribe(frequency=\"1d\")\n\ndef handle_data(context, data):\n    pass",
    "startDate": "2025-01-01",
    "endDate": "2025-12-31",
    "initialCapital": 10000,
    "leverageEnabled": false,
    "params": {}
  }'
```

Poll `/api/agent/v1/jobs/{job_id}` or consume `/api/agent/v1/jobs/{job_id}/stream`. Reuse an idempotency key when retrying the same submission.
Cancel a queued or running job with `POST /jobs/{job_id}/cancel` using B scope, confirmation at the MCP layer, and a new idempotency key. A running worker may finish its local computation, but it cannot overwrite the durable cancelled state.

## Indicators

Indicators are chart-only. Fetch `/indicators/authoring-contract`, validate with `/indicators/validate`, and save through `/indicators`. Indicator code cannot be passed to the backtest endpoint; convert the trading idea to Strategy API V2 first.

## Research, broker observations, and notifications

Research tools expose point-in-time universes, factor metadata, and the tenant watchlist under `/research/*`. Broker observation endpoints under `/trading/*` return safe credential metadata, account snapshots, account/strategy positions, pending orders, and cursor-paginated trade ledgers. They never return decrypted API keys, secrets, passphrases, or encrypted credential blobs.

N-scope signal-alert endpoints under `/notifications/signal-alerts` reuse the existing indicator notification service. Immediate evaluation requires explicit MCP confirmation because it may deliver a notification.

## Runtime and orders

`GET /runtime/overview` returns compact tenant runtime state. Quick orders require T scope and an `Idempotency-Key`. Live execution additionally requires a live-capable token, server live-trading enablement, a credential reference, client-side explicit confirmation, and compliance with the token's `max_order_notional` and `max_daily_notional` caps.

The emergency stop at `/quick-trade/kill-switch` requires `confirm=true`. It attempts to cancel open agent-originated live orders, cancels open paper orders, revokes all active T-scope tokens for the tenant, and returns any exchange cancellation failures for mandatory human review.

Rate limiting is shared through Redis across API workers and enforces both token and tenant quotas. Responses include `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset`; `429` responses also include `Retry-After`.

Never log tokens or credential material. Treat redacted values as terminal and do not attempt to reconstruct them.

---

## File: docs/agent/AI_INTEGRATION_DESIGN.md

# QuantDinger — AI / Agent Integration (Design)

| Item | Value |
|------|--------|
| Status | Draft (for review and phased rollout) |
| Audience | Maintainers; integrators wiring external AI agents into QuantDinger |
| Depends on | [AGENT_ENVIRONMENT_DESIGN.md](AGENT_ENVIRONMENT_DESIGN.md) — three-layer contracts |
| Repository | [QuantDinger](https://github.com/OpenByteInc/QuantDinger) |

> Companion to the multi-agent runtime design. That doc explains how *coding* agents work **inside the repo**. **This doc** explains how external and embedded **AI agents** consume QuantDinger as a **product** — research, strategy, backtest, and (carefully) execution.

---

## 1. Goals and non-goals

### 1.1 Goals

1. Treat **AI agents as first-class API consumers**, alongside the existing human web UI and in-product AI chat.
2. Provide a **stable, documented capability surface** so the same agent can do research, backtest, and supervised execution without screen-scraping the UI.
3. Enforce **least privilege, auditability, and kill-switches** before any money-adjacent automation is allowed.
4. Allow **multiple front doors** (HTTP / MCP / event stream) without forking business logic.

### 1.2 Non-goals (this phase)

- Not a marketplace of third-party plugins.
- No fully unattended live trading by an external LLM out-of-the-box. Live order routing requires explicit per-tenant opt-in and a documented allowlist.
- Not replacing the in-product AI chat (`ai_chat`) — this design is what that chat (and external agents) will call **underneath**.

---

## 2. Personas

| Persona | Example | Primary needs |
|---------|---------|---------------|
| **P1 Human trader** (existing) | QuantDinger user in browser | UI + REST + JWT session |
| **P2 In-product AI assistant** (existing) | `ai_chat` route, code-gen helpers | Same backend services, on behalf of a logged-in user |
| **P3 External coding agent** | Cursor / Claude Code / Codex working *in the repo* | Repository contracts (covered by `AGENT_ENVIRONMENT_DESIGN.md`) |
| **P4 External AI agent / app** *(new)* | Custom LLM workflow, MCP client, third-party automation | **Authenticated, scoped** access to research / backtest / (optional) trading |
| **P5 Autonomous strategy AI** *(gated)* | Generator → Strategy API V2 backtest → review → propose | Programmatic strategy deployment and bounded backtest jobs; no autonomous experiment/tuning service |

This document focuses on **P4 + P5**, keeping consistency with P1/P2.

---

## 3. Capability catalog

Capabilities are grouped by **risk class**. Every endpoint or MCP tool must declare exactly one class.

| Class | Examples | Default for new tokens |
|-------|----------|-------------------------|
| **R — Read** | Market data, klines, indicators, strategy listing, backtest results, account read | Allowed |
| **W — Workspace write** | Create/update Strategy API V2 deployments and save chart-indicator code | Allowed (workspace-scoped) |
| **B — Backtest / simulation** | Run Strategy API V2 backtests | Allowed |
| **N — Notifications & misc side-effects** | Send test notification, write user prefs | Allowed (rate-limited) |
| **C — Credentials** | Store/rotate exchange or LLM credentials | **Denied** by default; admin-only |
| **T — Trading / capital** | Quick trade, place/cancel order, adjust live strategy live capital | **Denied** by default; per-tenant explicit opt-in + allowlist |

**Rule:** A new agent token **cannot** acquire class `C` or `T` without an explicit operator action. Class `T` further requires a configured **paper / sandbox** path before it can be flipped to live.

Capability set is sourced from existing route groups: `market`, `kline`, `indicator`, `backtest`, `strategy`, `portfolio`, `dashboard`, `quick_trade`, `ibkr`, `polymarket`, `credentials`, `settings`, `community`, `fast_analysis`, `ai_chat`, `health`. The legacy experiment/tuning service is retired. New code should not add another way to trade; it should expose existing services with proper class tags.

---

## 4. Architecture

### 4.1 Layered view

```
                         ┌───────────────────────────────┐
                         │      External AI agents       │  P4 / P5
                         │  (LLM apps, MCP clients, ...) │
                         └──────────────┬────────────────┘
                                        │  HTTPS + Agent token
                                        ▼
┌─────────────────────────────┐   ┌────────────────────────────┐
│  Browser UI (existing)      │   │  Agent Gateway (NEW)       │
│  /api/...  + JWT session    │   │  /api/agent/v1/...         │
└──────────────┬──────────────┘   │  • token auth + scopes     │
               │                  │  • rate limit + audit log  │
               │                  │  • idempotency-key support │
               │                  └──────────────┬─────────────┘
               │                                 │
               ▼                                 ▼
        ┌───────────────────────────────────────────────┐
        │     Existing service layer (single source)    │
        │  market / strategies / backtest               │
        │  portfolio / quick_trade / credentials / ...  │
        └───────────────────────┬───────────────────────┘
                                │
                                ▼
              ┌───────────────────────────────────┐
              │  Postgres • Redis • Workers       │
              └───────────────────────────────────┘

                Optional, additive:
                ┌────────────────────────────────────┐
                │  MCP server (read-mostly subset)   │  --> Cursor / Claude-style clients
                │  thin wrapper over /api/agent/v1   │
                └────────────────────────────────────┘
```

Key decision: **the Agent Gateway is a thin layer**, not a parallel implementation. It reuses the same Flask services; it adds **identity, scopes, rate limits, idempotency, and a stable URL/version**.

### 4.2 URL and versioning convention

- **`/api/agent/v1/...`** — agent-facing namespace, stable contract.
- The browser UI keeps using `/api/...` as today; it may continue to evolve more freely.
- Breaking changes to the agent surface bump to `/v2`; `/v1` is supported for a defined window.

### 4.3 Identity model

- A **Tenant** is the existing QuantDinger user (single-user or multi-user mode).
- An **Agent token** belongs to a Tenant and carries:
  - `agent_id` (human-readable label, e.g. `cursor-mcp`, `strategy-bot-1`)
  - `scopes` (subset of capability classes from §3)
  - `markets` allowlist (e.g. `crypto`, `ibkr`)
  - `instruments` allowlist (optional, for trading scope)
  - `expires_at`
  - `paper_only` flag (default true for any token with `T`)
- Tokens are **prefixed and hashed at rest** (e.g. `qd_agent_xxx`); only the prefix is shown in audit logs.
- Existing JWT user sessions are **not** valid for `/api/agent/v1` and vice versa — separate auth pipelines, no accidental cross-use.

---

## 5. Endpoint shape (illustrative)

These are *contract sketches*, not committed routes. Final names follow `AGENT_ENVIRONMENT_DESIGN.md` Layer 3 conventions.

```
/* Detailed source-code truncated for AI context efficiency. */
```

### 5.1 Cross-cutting requirements

- **`Idempotency-Key` header** required for mutating class `W`, `B`, `N`, and `T` calls. The server atomically reserves method + route + key + request hash, replays completed responses, and rejects in-progress or mismatched reuse.
- **Async job pattern** for backtests to avoid long-lived HTTP and let LLMs poll.
- **Pagination** is explicit (`?limit=&cursor=`); no implicit caps.
- **Errors** follow a single envelope (`code`, `message`, `details`, `retriable`).
- **`X-RateLimit-*`** headers always returned.

---

## 6. Optional MCP layer

When integrators want **tool-style** rather than REST:

- Ship an **MCP server** that wraps a curated subset of `/api/agent/v1` (start with class `R` and `B`).
- The MCP server reads an **agent token** from its own config; it never asks the model for credentials.
- Tool descriptions explicitly state risk class and scope (e.g. `run_backtest (B, paper)`).

MCP is **additive**: REST stays the source of truth, MCP only re-shapes it for clients that prefer the protocol (Cursor, Claude-style, future tools).

---

## 7. Safety, audit, and ops

### 7.1 Trading safety (class T)

- Tokens default to `paper_only=true`. Real-money flip requires:
  1. Operator confirmation in the UI.
  2. A documented **allowlist** of instruments and max notional per order / per day.
  3. A **kill switch** that revokes all `T` tokens with one click and cancels open agent-originated orders.
- The Agent Gateway tags every order with `source=agent:<agent_id>` so portfolio, audit, and kill-switch logic can scope by agent.

### 7.2 Audit log

- One append-only log per tenant: `(ts, agent_id, route, scope_class, status, idempotency_key, redacted_request_summary)`.
- Stored alongside existing user activity; viewable per agent and per class in admin UI.
- Class `T` writes additionally include `(market, instrument, side, qty, est_notional, paper_or_live)`.

### 7.3 Rate limits and quotas

- Per-token: requests/min and concurrent backtest-job caps.
- Per-tenant: aggregate cap across all that tenant’s tokens.
- LLM-cost-bearing endpoints (e.g. anything proxying to `LLM_PROVIDER`) carry their **own** quota and are denied for tokens without an explicit `ai-llm` sub-scope.

### 7.4 Secrets and credentials

- Class `C` is admin-only; the Agent Gateway must never accept exchange API keys in request bodies for non-admin tokens.
- Existing encryption-at-rest (`SECRET_KEY` → Fernet for `qd_exchange_credentials.encrypted_config`) stays unchanged.

### 7.5 Multi-tenancy

- All queries through the Agent Gateway are forced through tenant-scoped service calls (no cross-tenant data leakage even on internal bugs).
- Test plan: an integration test that issues a token for tenant A and asserts every class-R route returns 404/403 for tenant B objects.

---

## 8. Deployment topologies (self-hosted vs SaaS)

QuantDinger ships as a **single backend** that intentionally supports two operational topologies. The Agent Gateway code is identical in both; the differences are entirely operator-controlled environment variables and where the database lives.

### 8.1 Topologies

| Dimension | **Self-hosted** (default) | **SaaS / shared / hosted** |
|-----------|---------------------------|----------------------------|
| Selector env var | `QUANTDINGER_DEPLOYMENT_MODE` unset (or `self`/`local`) | `QUANTDINGER_DEPLOYMENT_MODE=saas` (also `hosted`/`shared`/`multitenant`) |
| Tenants per instance | 1 (the operator) | N (one per signup) |
| Token issuance | Operator decides every field | Tenant users may issue T tokens; `paper_only=true` remains the default and C remains admin-only |
| Live trading (`AGENT_LIVE_TRADING_ENABLED`) | Operator may flip to `true` | Requires risk acknowledgement, a live-capable token, notional caps, and the deployment-wide server flag |
| Exchange credentials | Operator may store + use them | Recommended: do not accept; if you do, encrypt-at-rest and never expose via Agent Gateway (class C is admin-only) |
| Rate limits | Redis-backed per-token + per-tenant quotas | Same gateway quotas plus a per-IP outer proxy cap |
| Audit visibility | Operator | SaaS operator (you) sees everyone; tenant admins see only their own (already enforced by `user_id` filter in `/admin/audit`) |
| MCP `BASE_URL` | `http://localhost:8888` (or LAN URL) | `https://ai.quantdinger.com` (or your hosted URL) |

### 8.2 The hosted-mode guard (V3.1.0+)

When `QUANTDINGER_DEPLOYMENT_MODE` is a hosted spelling, self-service issuance still excludes C scope and defaults every T token to paper-only. A live-capable T token requires `ack_live_trading_risk=true`, positive per-order and per-day notional caps, and `AGENT_LIVE_TRADING_ENABLED=true`. The emergency stop revokes all tenant T tokens and reports any live exchange order that could not be cancelled.

This policy is covered by `tests/test_agent_v1_saas_guard.py`.

### 8.3 Recommended outer hardening for SaaS

Beyond the gateway controls, a hosted deployment should add at the proxy / infra layer:

- **HTTPS-only** with HSTS; no plaintext Agent token traffic.
- **Per-IP rate limiting** in front of the app, in addition to the Redis-backed token and tenant quotas.
- **CORS**: `/api/agent/v1/*` should not be exposed to browser CORS — agents call from servers / IDE subprocess / native code, not from web pages.
- **Quota / billing hook**: wrap `agent_jobs.submit_job` in billing middleware when future job kinds consume paid services.
- **Token reveal hygiene**: full token shown once in the Vue admin UI, never logged, never echoed back from `/admin/tokens` GET. Already enforced.

### 8.4 Migration between topologies

Switching a running deployment from self-hosted to SaaS is non-destructive:

```bash
# Add to the env file used by docker-compose
QUANTDINGER_DEPLOYMENT_MODE=saas
docker compose up -d backend
```

After restart:
- Existing T-scope tokens **continue to work** (the guard runs at issuance, not on each request) — the operator should `DELETE /admin/tokens/{id}` for any token they no longer want active under SaaS rules. A future enhancement may add a one-shot "revoke all T tokens on mode change" startup task.
- New issuances follow SaaS rules immediately.

### 8.5 Why a single binary serves both

We deliberately did **not** fork SaaS into a separate codebase:

- **Less drift**: every bug fix and feature ships to both topologies on the same release.
- **Self-host parity**: enterprise/private users get bit-for-bit identical Agent Gateway behavior to the hosted demo, so trust transfers.
- **Test surface**: the `_is_saas_mode()` branch is a single env-var check, easy to cover (and is, in `test_agent_v1_saas_guard.py`).

---

## 9. Mapping to existing code

| Concern | Existing code | Reuse strategy |
|---------|----------------|----------------|
| User auth (JWT) | `app/routes/auth.py`, `app/utils/auth.py` | Keep. Agent tokens live in a parallel module (`app/utils/agent_auth.py` proposed). |
| Trading | `quick_trade`, `ibkr`, `polymarket` | Wrap in `T`-class endpoints; reuse service layer; do **not** fork order logic. |
| Backtest | `backtest`, `app/services/strategy_v2/*` | Keep long-running entrypoints behind the async job table; agent endpoints remain thin submit/poll wrappers. |
| AI chat / code-gen | `ai_chat` | Refactor to call internal services; agent endpoints expose the same services without the chat shell. |
| Health | `health` | Reuse for `/api/agent/v1/health`. |

No new Python packages are required for the gateway itself; storage uses existing Postgres (new tables: `qd_agent_tokens`, `qd_agent_jobs`, `qd_agent_audit`).

---

## 10. Phased roadmap

| Phase | Deliverable | Risk class enabled | Human action required |
|-------|-------------|--------------------|------------------------|
| **A0** | Spec freeze: this doc + endpoint table + scope schema | — | Review and merge |
| **A1** | Agent token issuance + `/api/agent/v1/health`, `markets`, `symbols`, `klines`, `indicators/run` | R | Issue first token in admin UI |
| **A2** | Strategies CRUD + backtest async jobs + audit log v1 | R, W, B | Per-tenant opt-in for W |
| **A3** | Per-token rate limits and bounded job streaming | R, W, B | — |
| **A4** | Optional MCP server wrapping the current Agent Gateway | R, B, W | Configure MCP client |
| **A5** | Trading endpoints in **paper-only** mode + per-agent kill switch | T (paper) | Explicit per-token opt-in |
| **A6** | Live trading promotion path: instrument allowlist, notional caps, dual-control toggle | T (live) | Operator dual confirmation |

A1–A4 are **safe to ship without trading exposure**. A5/A6 are gated and reversible.

---

## 11. Open questions

1. **Token storage location** — share `qd_users` table family vs new schema namespace?
2. **Job runner** — reuse existing worker toggles (`ENABLE_PENDING_ORDER_WORKER`, etc.) or introduce a dedicated `agent-jobs` worker? Prefer the latter for blast-radius isolation.
3. **OpenAPI generation** — auto-derive from Flask blueprints or hand-maintain a single `agent-openapi.json` checked into `docs/agent/`?
4. **MCP transport** — stdio first (simplest for desktop IDEs), HTTP later for cloud agents.
5. **Cost passthrough** — when class `B` triggers LLM use indirectly (e.g. NL→code helpers), should the response include token-cost telemetry?

---

## 12. Implementation status

| Area | Status | Where it lives |
|------|--------|----------------|
| Schema (tokens / jobs / audit / paper-orders) | Shipped | `backend_api_python/migrations/init.sql` (section 30) + runtime ensure in `app/utils/agent_auth.py` |
| Token auth + scopes + distributed token/tenant quotas + audit | Shipped | `app/utils/agent_auth.py` |
| Atomic idempotency for W/B/N/T mutations | Shipped | `qd_agent_idempotency` + `agent_required` |
| Async job runner, progress, and cancellation | Shipped | `app/utils/agent_jobs.py` |
| Read endpoints (R) | Shipped | `app/routes/agent_v1/{health,markets,strategies,jobs,portfolio,research,trading_data}.py` |
| Workspace endpoints (W) | Shipped | `app/routes/agent_v1/{strategies,strategy_sources,indicators,research}.py` |
| Notification automation (N) | Shipped | `app/routes/agent_v1/notifications.py` |
| Strategy API V2 backtest endpoint (B) | Shipped | `app/routes/agent_v1/backtests.py` |
| Trading endpoints (T) — paper and hard-gated live | Shipped | `app/routes/agent_v1/quick_trade.py` (allowlists, token notional caps, server flag, emergency stop) |
| Admin token CRUD + audit viewer | Shipped | `app/routes/agent_v1/admin.py` |
| OpenAPI 3.0 spec | Shipped | `docs/agent/agent-openapi.json` |
| MCP server (Python) | Shipped | `mcp_server/` — `stdio` (default), `sse`, and `streamable-http` transports via `QUANTDINGER_MCP_TRANSPORT` |
| Operator quickstart | Shipped | `docs/agent/AGENT_QUICKSTART.md` |
| Job progress streaming (SSE) | Shipped | `GET /api/agent/v1/jobs/{id}/stream` — `snapshot` / `progress` / `ping` / `result` frames; resume via `?since=` or `Last-Event-ID` |
| Token UI (Profile + admin audit) | Shipped | `ProfileAgentTokens.vue` at Profile → My Agent Token (`/api/agent/v1/me/tokens`); admin route `/agent-tokens` retained |
| Hosted-mode hardening (`QUANTDINGER_DEPLOYMENT_MODE=saas`) | Shipped | C scope stays admin-only; T defaults paper-only and live eligibility requires explicit risk acknowledgement |
| Published MCP package on PyPI | Shipped | [`quantdinger-mcp`](https://pypi.org/project/quantdinger-mcp/) — install via `pipx`, `uvx`, or `pip` |
| Live quick-order execution (T, self-host only) | Shipped, hard-gated | `app/routes/agent_v1/quick_trade.py`; requires live-capable token, explicit MCP confirmation, credential, and server flag |

## 13. Revision history

| Version | Date | Notes |
|---------|------|--------|
| 0.1 | 2026-05-02 | First draft: personas, capability classes, gateway, MCP, safety, roadmap |
| 0.2 | 2026-05-02 | A0–A5 implemented (schema, auth, R/W/B + paper-only T, admin, MCP, tests, OpenAPI, quickstart) |
| 0.3 | 2026-05-02 | Added: SSE progress streaming for jobs, MCP HTTP/SSE transport, Vue admin UI for token & audit management |
| 0.4 | 2026-05-02 | Added §8 Deployment topologies; shipped hosted-mode guard (`QUANTDINGER_DEPLOYMENT_MODE=saas` → T-scope rejected, `paper_only` pinned); MCP package published to PyPI; README EN/CN now documents the SaaS vs self-host paths side-by-side |
| 0.5 | 2026-07-31 | Added full research/observation/notification MCP surface, atomic idempotency, Redis quotas, job cancellation, notional caps, and tenant emergency stop |

---

## File: docs/agent/MCP_SETUP.md

# MCP Setup

QuantDinger's MCP server wraps the Agent Gateway and keeps the REST API as the source of truth.

## Install

```bash
pip install "quantdinger-mcp==0.5.0"
```

For repository development, use `pip install -e ./mcp_server` instead.

Set these environment variables in the MCP client process:

```text
QUANTDINGER_BASE_URL=http://localhost:8888
QUANTDINGER_AGENT_TOKEN=qd_agent_xxx
```

Run `quantdinger-mcp` for the default `stdio` transport. For network use, set `QUANTDINGER_MCP_TRANSPORT=sse` or `streamable-http`, plus optional `QUANTDINGER_MCP_HOST` and `QUANTDINGER_MCP_PORT`.

Non-loopback network listeners are denied by default unless `QUANTDINGER_MCP_AUTH_TOKEN` is set to a distinct secret of at least 32 characters. Configure `QUANTDINGER_MCP_PUBLIC_URL` to the externally reachable HTTPS base URL and send the inbound token as a Bearer token from the MCP client. The inbound token protects the MCP listener; `QUANTDINGER_AGENT_TOKEN` remains the separate upstream tenant credential.

## Client configuration

A typical stdio client entry is:

```json
{
  "mcpServers": {
    "quantdinger": {
      "command": "quantdinger-mcp",
      "env": {
        "QUANTDINGER_BASE_URL": "http://localhost:8888",
        "QUANTDINGER_AGENT_TOKEN": "qd_agent_xxx"
      }
    }
  }
}
```

Keep the configuration private. Prefer an environment-secret facility when the client supports one.

## Expected workflow

- Use market tools for discovery and OHLCV reads.
- Use universe, factor, and watchlist tools for research workspace inputs.
- Use indicator tools only for chart artifacts.
- Compile Strategy API V2 code before saving it.
- Save private Strategy API V2 sources and inspect version history.
- Create stopped deployments from saved V2 source IDs.
- Use bounded job polling or SSE streaming for backtest results.
- Use broker and execution observation tools only for reads; credential secrets are never exposed.
- Use N-scope signal-alert tools for notification automation.
- Supply a unique `idempotency_key` to every mutating W/B/N/T tool.
- Require explicit confirmation before restoring source versions, cancelling jobs, deleting alerts, delivering notifications, stopping runtime state, emergency-stopping trading, or placing any order.

The strategy manifest owns market, instrument, frequency, warmup, dependency, and leverage scope. Do not pass those as alternate backtest fields.

For the exact tool signatures, see [the MCP package README](../../mcp_server/README.md) and [Agent OpenAPI](agent-openapi.json).

---

## File: docs/agent/README.md

# Agent documentation (English)

This folder holds **agent-facing** material for coding assistants (Cursor, Claude Code, Codex, CLI bots, etc.).

| Document | Purpose |
|----------|---------|
| [MCP_SETUP.md](MCP_SETUP.md) | Wire Cursor / Claude Code / Codex / remote agents to a QuantDinger backend via the `quantdinger-mcp` MCP server (local stdio + remote HTTP) |
| [AGENT_ENVIRONMENT_DESIGN.md](AGENT_ENVIRONMENT_DESIGN.md) | Architecture: layered contracts (docs → commands → API/MCP), security boundaries, roadmap, implementation checklist |
| [AI_INTEGRATION_DESIGN.md](AI_INTEGRATION_DESIGN.md) | How external AI agents (P4) and autonomous strategy AIs (P5) consume QuantDinger via a versioned, scoped Agent Gateway |
| [AGENT_QUICKSTART.md](AGENT_QUICKSTART.md) | Operator + integrator walkthrough: issue a token, call the Gateway, run paper trades |
| [agent-openapi.json](agent-openapi.json) | Machine-readable contract for `/api/agent/v1` (OpenAPI 3.0) |
| [../architecture/API_CONVENTIONS.md](../architecture/API_CONVENTIONS.md) | Shared HTTP conventions (envelopes, auth, Public/Internal tiers) |
| [../api/openapi.yaml](../api/openapi.yaml) | Human Web API spec (flask-smorest; migration in progress) |

**Language policy:** Agent-oriented docs and [`.cursor/skills/`](../../.cursor/skills/) in this repository are **English only** so the same text works across tools and locales.

For human product overviews in other languages, see the root [README.md](../../README.md) and [docs/README_CN.md](../README_CN.md).