This commit is contained in:
2026-09-09 11:35:02 +08:00
parent bc1c72d558
commit d656c05b3d
35 changed files with 711 additions and 3194 deletions

View File

@@ -9,21 +9,24 @@
## 快速启动
两个终端分别启动后端与前端:
两个终端分别启动后端与前端(命令均从仓库根 `stock/` 执行)
```bash
# 终端 1 —— 后端 APIhttp://localhost:8000
cd backend
env -u SSLKEYLOGFILE uv run uvicorn app.main:app --reload --port 8000
bash backend/restart_backend.sh
# 终端 2 —— 前端开发服务器http://localhost:5173
cd frontend
pnpm dev
```
> `env -u SSLKEYLOGFILE` 是本机Windows必需的用户环境变量 `SSLKEYLOGFILE` 值开头混有不可见控制符asyncpg 建连即崩。详见下文「快速开始(开发模式)」与「常见问题」
> 后端统一走 `backend/restart_backend.sh`:自动杀旧进程树 + 剔除会崩 asyncpg 的 `SSLKEYLOGFILE` + 带热重载重启 + 日志写 `backend_run.log`。Windows cmd 下等价命令:`backend\restart_backend.cmd`。详见下文「快速开始(开发模式)」。
**首次运行前**
1. 装依赖:后端 `cd backend && uv sync`、前端 `cd frontend && pnpm install`
2. 后端依赖 **PostgreSQL16/17+ Redis 已启动**,并配好 `backend/.env`(复制 `.env.example`)。
3. 建库表:`cd backend && uv run alembic upgrade head`
首次运行前先安装依赖:后端 `uv sync`backend 下)、前端 `pnpm install`frontend 下)。
浏览器打开 http://localhost:5173 即可使用。详细说明见下文「快速开始(开发模式)」。
---
@@ -67,28 +70,36 @@ stock/
├── TECH_STACK.md # 技术选型与架构决策(必读)
├── README.md # 本文件
├── backend/ # FastAPI + 回测引擎
│ ├── pyproject.toml # uv 依赖声明
│ ├── pyproject.toml # uv 依赖声明pytest 在 dev 组)
│ ├── .env.example # 配置示例(数据库 / 费率)
│ ├── smoke_test.py # 后端全链路自检脚本
│ ├── smoke_test.py # 后端全链路自检脚本(线上库鉴权+核心 API
│ ├── conftest.py # pytest 根(使 tests/ 可直接 import app.*
│ ├── tests/ # pytest 单元测试(交割单解析/复权换算/缓存/限速/事件回测纯函数)
│ ├── scripts/ # 一次性运维脚本TDX 导入 / 复权因子回补…)
│ └── app/
│ ├── main.py # FastAPI 入口(启动建表
│ ├── main.py # FastAPI 入口(lifespan 拉起夜间调度
│ ├── config.py # 配置pydantic-settings
│ ├── db.py # async SQLAlchemy 引擎/会话
│ ├── domain.py # 领域契约Bar/Signal/Fill/Position…
│ ├── models.py # ORMCandle / BacktestRun
│ ├── models.py # ORMCandle / StockBasic / 用户数据表…
│ ├── schemas.py # Pydantic DTO= OpenAPI 契约)
│ ├── commission.py # A 股交易成本(已修正、可配置
│ ├── auth.py # Argon2 密码 + 会话SHA-256 摘要
│ ├── auth_api.py # 登录/登出(含按 IP 限速)
│ ├── scheduler.py # 夜间定时任务(收盘后自动同步 + 会话清理)
│ ├── cache.py # Redis 读缓存(本地层 + 版本号失效 + 熔断冷却恢复)
│ ├── indicators.py # 指标MACD/RSI/KDJ/布林/均线(单一事实源)
│ ├── api.py # 路由/health /candles /backtest
│ ├── data/ # DataProvider 适配器Tushare/AKShare+ 周期聚合
── backtest/ # engine / broker(PaperBroker) / metrics / strategies
│ ├── api/ # 路由stocks / etfs / market / backtest / screener / user + _deps 共享件
│ ├── data/ # 数据管道tushare 适配 + 同步 + 懒加载缓存)
── screener/ # 智能选股LLM 解析 + 全市场引擎 + 夜间同步)
│ └── backtest/ # engine / events(全市场事件回测) / strategies
└── frontend/ # Vue SPA
├── src/
│ ├── main.ts # PrimeVue(Aura 深色) + Pinia
│ ├── main.ts # Vue + Pinia
│ ├── api/ # 类型化客户端 + DTO 镜像
│ ├── stores/ # Pinia 回测状态
│ ├── components/ # KLineChart / EquityChart / MetricsPanel / BacktestForm
── views/ # BacktestView
│ ├── stores/ # Pinia(鉴权/设置/同步状态
│ ├── composables/ # 组合式工具(防抖 ref / 路由 query 同步)
── components/ # StockDetailOverlay / DetailKLine / LimitBoard / MarketOverview
│ └── views/ # Home / Stocks / ETF / Concepts / Indexes / Screener / Backtest
└── vite.config.ts # /api 代理到 :8000
```
@@ -117,17 +128,16 @@ pip install uv
### 1) 后端
实际启动命令(venv 解释器直启,日志重定向到仓库根 `backend_run.log`,改代码自动热重载
实际启动命令(一键脚本,自动杀旧进程树 + 剔除 SSLKEYLOGFILE + 热重载 + 日志写仓库根 `backend_run.log`
```bash
cd backend
uv sync # 创建 .venv 并安装依赖(仅首次)
env -u SSLKEYLOGFILE .venv/Scripts/python.exe -m uvicorn app.main:app --reload --port 8000 > ../backend_run.log 2>&1
uv sync # 创建 .venv 并安装依赖(仅首次)
bash backend/restart_backend.sh # 从仓库根执行Git BashWindows cmd 下等价backend\restart_backend.cmd
```
看日志:`tail -f backend_run.log`;确认起没起:`curl http://localhost:8000/api/health`
等价的 `uv run` 写法(不带日志重定向,直接打到当前终端):
等价的 `uv run` 写法(不杀旧进程、日志直接打到当前终端):
```bash
cd backend
@@ -135,13 +145,15 @@ env -u SSLKEYLOGFILE uv run uvicorn app.main:app --reload --port 8000
```
- **`env -u SSLKEYLOGFILE`(本机 Windows 必需)**:用户环境变量 `SSLKEYLOGFILE` 的值开头混有 U+202A 不可见控制符asyncpg 建连时执行 `ssl.keylog_filename` 直接抛 `OSError: [Errno 22]`uvicorn 启动即崩。Git Bash 下用 `env -u` 剔除即可;根治可 `setx SSLKEYLOGFILE "C:\Users\cirry\Desktop\fhzg.log"`(重开终端后不再需要前缀)。验证:`python -c "import os; print(repr(os.environ.get('SSLKEYLOGFILE')))"`
- **Windows `--reload` 僵死**watcher 偶尔改文件不重载且日志无 Reloading 行,此时只能杀进程树重启——`netstat -ano | grep :8000` 找 PID`taskkill //PID <pid> //T //F`
- **Windows `--reload` 僵死**watcher 偶尔改文件不重载且日志无 Reloading 行,此时只能杀进程树重启——一键脚本 `bash backend/restart_backend.sh`Git Bash`backend\restart_backend.cmd`cmd自动杀旧进程树`--reload` 起 launcher→reloader→worker 三层进程)+ 带 reload 重启 + 日志写 `backend_run.log`。手动:`netstat -ano | grep :8000` 找 PID`taskkill //PID <pid> //T //F`
- 数据库结构由 Alembic 管理:首次部署/更新代码后先执行 `uv run alembic upgrade head`(见「初始化登录系统」)。
- 交互式 API 文档http://localhost:8000/docs
- **夜间自动同步**:后端启动即拉起调度(`app/scheduler.py`),每日 18:05 本地时间自动跑全市场 A 股 + ETF 同步并清理过期会话;进程启动时若已过点且当日数据未落库会补跑。关闭:`.env``NIGHTLY_SYNC_ENABLED=false`,时间改 `NIGHTLY_SYNC_HOUR`
**自检**(无需起服务器,验证全链路)
**测试**
```bash
uv run --with httpx --directory backend python smoke_test.py
uv run --directory backend pytest -q # 单元测试(交割单解析/复权换算/缓存/限速等纯函数,不碰库)
uv run --with httpx --directory backend python smoke_test.py # 全链路自检(线上库鉴权+核心 API
```
### 2) 前端
@@ -152,7 +164,8 @@ pnpm install # 首次
pnpm dev # http://localhost:5173
```
前端 `/api` 请求由 Vite 代理到后端 `:8000` `vite.config.ts`),无需处理跨域
- **必须用 pnpm不要用 npm/yarn**:项目锁定 `pnpm-lock.yaml``node_modules` 是 pnpm 的硬链接结构,`npm install` 会写坏依赖,导致装包/构建崩溃。以后装包一律 `pnpm add <pkg>`不要 `npm install <pkg>`
- 前端 `/api` 请求由 Vite 代理到后端 `:8000`(见 `vite.config.ts`),无需处理跨域。
打开 http://localhost:5173 → 选周期、改参数 → 点「开始回测」。
鼠标悬停 K 线可看当日详情弹框;切日线/周线/月线/年线勾「fast 模式」可对比关闭费用/T+1 的差异。
@@ -229,9 +242,10 @@ EXPOSE_API_DOCS=false
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | `/api/health` | 健康检查 |
| GET | `/api/candles/{symbol}?timeframe=1d&limit=1000` | 取 K 线(`timeframe`: `1d`/`1w`/`1M`/`1y` |
| POST | `/api/data/sync` | 拉取并缓存某标的日线Tushare 主 → AKShare 兜底。body: `{symbol, source?, force?}` |
| POST | `/api/backtest` | 跑回测(真实标的首次自动拉取并缓存) |
| POST | `/api/backtest` | 跑回测(真实标的首次自动拉取并缓存;前端已改用 `/api/backtest/event` 事件回测,此为旧策略回测 API |
个股 K 线统一走 `GET /api/screener/preview/{ts_code}`(含复权/指标预热/翻页,两级缓存)。
**回测请求示例**
```json