You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -165,7 +165,7 @@ QuantDinger is a **self-hosted, local-first** quantitative infrastructure layer
165
165
|**Agent-native**| First-class **Agent Gateway** (`/api/agent/v1`) + **[`quantdinger-mcp`](https://pypi.org/project/quantdinger-mcp/)** on PyPI — Cursor, Claude Code, and Codex can read markets, run backtests, and trade (paper by default) with full audit logs. |
166
166
|**Dual strategy runtimes**|**`IndicatorStrategy`** (four-way dataframe signals + chart overlays) and **`ScriptStrategy`** (event-driven `on_bar`, explicit orders) — research and production in the same codebase. |
167
167
|**Multi-venue execution**| Direct adapters for Binance, OKX, Bitget, Bybit, Gate, HTX, Coinbase Exchange, Kraken, **IBKR**, and **Alpaca** — unified Broker Accounts page with isolated multi-tenant sessions. |
|**Security by default**| Refuses default `SECRET_KEY`, agent tokens hashed at rest, **paper-only trading** unless explicitly unlocked server-side, every agent call audit-logged. |
170
170
|**Operator-ready**| OAuth, multi-user roles, credits/membership/USDT billing toggles, an 11-language web UI, and multilingual docs — build a commercial quant product on top, not just a hobby bot. |
-**Build** — Professional KLine chart UI; `IndicatorStrategy` (four-way dataframe signals: `open_long`, `close_long`, `open_short`, `close_short`) and `ScriptStrategy` (`on_bar`, `ctx.buy()` / `ctx.sell()`); AI code generation as a starting point, Python as source of truth.
236
236
-**Validate** — Server-side backtests with equity curves, drawdown metrics, trade logs, and strategy snapshots — no client-side-only backtest theater.
237
237
-**Operate** — Live strategy bots, quick trade, crypto spot/swap execution through direct exchange adapters, **IBKR** / **Alpaca** workflows for traditional markets; unified **Broker Accounts** page; notifications (Telegram, email, SMS, Discord, webhooks).
238
-
-**Platform** — Docker Compose + GHCR images, PostgreSQL 16, Redis 7, OAuth, multi-user RBAC, credits / membership / USDT billing toggles, an 11-language web UI, and multilingual documentation.
238
+
-**Platform** — Docker Compose + GHCR images, PostgreSQL 18, Redis 7, OAuth, multi-user RBAC, credits / membership / USDT billing toggles, an 11-language web UI, and multilingual documentation.
239
239
240
240
## Architecture
241
241
242
242
**Design principle:** separate **market data ingestion**, **strategy/backtest compute**, and **order execution** so research never shares a code path with live capital unless you explicitly promote a strategy.
243
243
244
-
**Stack:** Nginx serves the prebuilt Vue SPA (`ghcr.io/brokermr810/quantdinger-frontend`); **Flask + Gunicorn** API hosts strategy, AI, billing, and agent services; **PostgreSQL 16** is the system of record; **Redis 7** backs cache and worker coordination. Exchanges, brokers, LLMs, and payment rails plug in through env-driven adapters — swap providers without forking core code.
244
+
**Stack:** Nginx serves the prebuilt Vue SPA (`ghcr.io/brokermr810/quantdinger-frontend`); **Flask + Gunicorn** API hosts strategy, AI, billing, and agent services; **PostgreSQL 18** is the system of record; **Redis 7** backs cache and worker coordination. Exchanges, brokers, LLMs, and payment rails plug in through env-driven adapters — swap providers without forking core code.
245
245
246
246
**Runtime flow:** market feeds → indicator/signal layer → strategy engine → backtest or live runtime → venue-specific execution adapters; pending orders dispatched by background workers with health checks and retry semantics.
Almost all runtime behavior is driven by **`backend_api_python/.env`** (database URL, admin user, LLM keys, workers, billing toggles, etc.). The optional **repository root**`.env` only adjusts Compose-level concerns such as **ports** and **image mirrors** (`IMAGE_PREFIX`).
334
+
Almost all application behavior is driven by **`backend_api_python/.env`** (admin user, LLM keys, workers, billing toggles, broker settings, etc.).
335
+
336
+
The optional **repository root**`.env` is for Docker Compose orchestration: exposed ports, image mirrors (`IMAGE_PREFIX`), image tags, Postgres image/version, Postgres data mount, `PGDATA`, and the Compose-generated `DATABASE_URL`. Keep this boundary clear:
337
+
338
+
| File | Owns |
339
+
|------|------|
340
+
|`backend_api_python/.env` or `backend.env`| Application runtime settings used by the Flask API. |
341
+
| Repository-root `.env`| Docker Compose substitutions such as ports, image tags, Postgres/Redis wiring, and host paths. |
335
342
336
343
### 3) Set `SECRET_KEY` and admin credentials before the first boot (mandatory)
337
344
@@ -370,6 +377,46 @@ docker compose up -d
370
377
371
378
Services: **`postgres`**, **`redis`**, **`backend`**, **`frontend`**, **`mobile`** (see `docker-compose.yml`).
372
379
380
+
#### Existing PostgreSQL data or 1Panel migration
381
+
382
+
For a fresh install, do nothing: Compose creates its own Postgres volume.
383
+
384
+
For an existing production database, prefer `pg_dump` / `pg_restore` when the dataset is manageable. If the data directory is too large and must be mounted directly, all of these must match:
385
+
386
+
- The Postgres **major version** of the image and the existing data directory.
387
+
- The exact container `PGDATA`.
388
+
- The database user/password that already exist inside that data directory.
389
+
- Only one Postgres container may use that physical directory at a time.
Then stop the old database container, recreate the new one, and verify:
411
+
412
+
```bash
413
+
docker compose up -d postgres
414
+
docker compose logs --tail=100 postgres
415
+
docker compose up -d backend frontend mobile redis
416
+
```
417
+
418
+
Do **not** mount a PostgreSQL 16 data directory into a PostgreSQL 18 image, or the database will fail with `database files are incompatible with server`.
419
+
373
420
#### Alternative: zero-repo install from GHCR (lightest)
374
421
375
422
Prebuilt multi-arch (amd64/arm64) images for **both** backend and frontend — no `git clone`:
@@ -459,6 +506,19 @@ In the normal Docker stack, you usually do **not** need to edit a frontend API U
459
506
460
507
For LAN testing on a phone, do not use `localhost` inside the phone browser. Use the host machine's LAN IP, such as `http://192.168.1.10:8889`.
461
508
509
+
### 5.2) Production runtime checks
510
+
511
+
The Compose backend runs the API with **Gunicorn** and sets `nofile` to `65535`. That is the recommended production path. Avoid running the backend with `python run.py` on a public server; it is meant for development and commonly inherits a low file-descriptor limit such as `1024`.
512
+
513
+
After deployment, quick-check the backend container:
Expected: `ulimit -n` is high enough for your user scale, and the command line contains Gunicorn. If you deploy through 1Panel or another custom runtime, set the equivalent `nofile` limit there and point the reverse proxy at the running backend port.
521
+
462
522
### 6) Optional: enable AI features
463
523
464
524
AI analysis, NL→code, and related flows need at least one LLM provider configured. Open `backend_api_python/env.example`, find the **AI / LLM** block, copy the relevant keys into your `.env` (for example `LLM_PROVIDER` + `OPENROUTER_API_KEY`, or another supported provider). Restart the backend after edits.
@@ -499,6 +559,10 @@ If `py` is not on PATH, use `python` or `python3` in the one-liner that generate
499
559
|`redis` / `python` / `node` pull fails, `content size of zero`| Docker Hub unreachable from Docker Desktop. Set root `.env``IMAGE_PREFIX=docker.m.daocloud.io/library/` and/or configure **Docker Desktop → Proxies** (system VPN alone is often not enough). |
500
560
| Backend exits immediately |`SECRET_KEY` still default, or invalid `.env` syntax. Read `docker compose logs backend`. |
501
561
| Blank page or API errors from browser |`FRONTEND_URL` / origins mismatch; API not reachable from the host you opened. |
562
+
| Browser shows `502 Bad Gateway`| The reverse proxy cannot reach the backend. Check `docker compose ps`, `docker compose logs --tail=100 backend`, and make sure Nginx/OpenResty points to `quantdinger-backend:5000` inside Compose or to the exposed host port. |
563
+
|`database files are incompatible with server`| The Postgres image major version does not match the mounted data directory. Set `POSTGRES_IMAGE` to the existing data major version, or restore through `pg_dump` / `pg_restore`. |
564
+
|`password authentication failed for user ...`| The root `.env``POSTGRES_USER` / `POSTGRES_PASSWORD` or `DATABASE_URL` does not match the user stored in the existing data directory. Fix the root `.env`, then recreate the backend container. |
565
+
|`Too many open files` or `ulimit -n` is `1024`| Use the bundled Compose backend or configure your custom runtime with `nofile` around `65535`, then recreate the container. Restarting without recreating usually keeps the old limit. |
502
566
| Mobile or web source dev calls the wrong backend | Use `VITE_DEV_PROXY_TARGET` for `QuantDinger-Vue`, `VITE_DEV_API_TARGET` for `QuantDinger-Mobile`, and restart the dev server after changing env vars. |
503
567
| Mobile source dev fails with `crypto.hash is not a function`| Node is too old for Vite 7. Install/switch to Node 22 LTS (or at least Node 20.19+ / 22.12+). |
504
568
| Port already in use | Another Postgres, Redis, or local service on `5432` / `6379` / `5000` / `8888` / `8889`. Adjust variables in root `.env` per `docker-compose.yml`. |
@@ -518,13 +582,22 @@ docker compose down
518
582
519
583
### Optional root `.env` (Compose only)
520
584
521
-
For **custom ports** or **mirror/prefix** for base images (slow Docker Hub pulls), create a file named `.env` in the **repository root** (same directory as `docker-compose.yml`):
585
+
For **custom ports**, **mirror/prefix** for base images, image tags, or Postgres physical data mounts, create a file named `.env` in the **repository root** (same directory as `docker-compose.yml`):
522
586
523
587
```ini
524
588
FRONTEND_PORT=3000
525
589
MOBILE_PORT=3001
526
590
BACKEND_PORT=127.0.0.1:5001
527
591
IMAGE_PREFIX=docker.m.daocloud.io/library/
592
+
593
+
# Optional: reuse an existing PostgreSQL 18 data directory.
594
+
# Stop the old Postgres container before mounting this path.
0 commit comments