Files
trade/CLAUDE.md
2026-05-03 22:31:19 +08:00

94 lines
7.2 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## 项目概述
基于 Docker + Python(tushare) + PostgreSQL 的中国期货行情分析系统,实现日线数据采集与三层加权打分模型。运行方式支持两种模式:① 宿主机 cron/launchd 定时调用 `docker-compose run` 执行 CLI;② 通过 FastAPI 服务以 HTTP API 触发。详细业务说明见 `README.md`
## 常用命令
```bash
# === 启动全栈服务(PostgreSQL + tushare API + web) ===
docker-compose -f docker-compose.trade.yml up -d
# === tushare CLI(不传参 = 按当月 FG 主力自动选合约,轮换规则见 contracts.py:ROLLOVER_RULES) ===
docker-compose -f docker-compose.trade.yml run --rm tushare python -m src.main
# 显式指定合约(注意交易所后缀:.ZCE/.SHF/.DCE,郑商所是 .ZCE 不是 .CZC)
docker-compose -f docker-compose.trade.yml run --rm tushare python -m src.main RB2510.SHF
# 用品种代号自动选当月主力(目前只配置了 FG)
docker-compose -f docker-compose.trade.yml run --rm tushare python -m src.main --symbol FG
# === tushare API 服务(容器内运行 uvicorn,端口 8000) ===
# 触发单次流水线
curl -X POST http://localhost:4001/api/v1/run -H "Content-Type: application/json" \
-d '{"symbol":"FG"}'
# 批量触发所有固定品种今日打分
curl -X POST http://localhost:4001/api/v1/run/batch
# 查询打分列表
curl "http://localhost:4001/api/v1/scores?limit=5"
# === 修改代码后必须重建镜像 ===
docker-compose -f docker-compose.trade.yml build tushare
docker-compose -f docker-compose.trade.yml build web
# === 查最新打分(PostgreSQL) ===
docker-compose -f docker-compose.trade.yml exec postgres psql -U trade -d futures -c \
"SELECT ts_code, trade_date, composite, signal FROM scores ORDER BY trade_date DESC LIMIT 5;"
```
## 关键架构
**单进程串行流水线**:`src.main.main()` 先按命令行参数(显式 `ts_code` 优先,否则 `contracts.active_contract(symbol)` 按当月主力自动选)定下合约,再调 `run()` 顺序执行 `fetcher → storage(candles) → scorer → storage(scores)`。无后台任务、无队列,每次 CLI 调用处理一个合约一日。
**FastAPI 服务**(`src.api`):容器默认以 `uvicorn src.api:app` 启动,暴露 `/api/v1/run`(触发流水线)、`/api/v1/run/batch`(批量打分)、`/api/v1/scores``/api/v1/scores/{id}``/api/v1/contracts``/api/v1/candles` 等端点。启动时自动 `storage.init_db()` 建表。API 与 CLI 共用同一套 `fetcher/storage/scorer` 逻辑。
**主力轮换规则**(`contracts.py`):每个品种在 `ROLLOVER_RULES` 中维护 `month -> (主力月, 年份偏移)` 表。FG 当前规则:1-3/12 月→05、4-7 月→09、8-11 月→01,其中 8-11 月与 12 月跨年(`year_offset=1`)。新增品种(如 RB、I)只需在该 dict 里加一条,无需改 main 流程。
**三层打分模型**(`scorer.py`):综合 = 短期(7日,0.4) + 中期(15日,0.35) + 长期(30日,0.25)。`score_daily()` 要求 DataFrame ≥31 行,`fetcher.fetch_contract` 默认拉一个合约的全历史(实际 100+ 行),按 `trade_date` 升序排列后供打分使用。打分结果通过 `dataclass ScoreResult` + `ScoreDetail` 流转,`storage.save_score` 把 detail 序列化为 `detail_json` 文本列。
**PostgreSQL 作为业务数据库**:docker-compose 编排 `postgres:18.3-alpine3.23`,`tushare``web` 服务均通过 `DATABASE_URL` 连接。`storage.py` 使用 `psycopg3` 驱动,`candles``scores` 表以 `ON CONFLICT (ts_code, trade_date) DO UPDATE` 实现幂等,可反复重跑同一天。`scores` 表主键为 `UUID DEFAULT uuidv7() PRIMARY KEY`(见 `models.py``storage.py`)。
**Docker 边界**:`tushare/src/``web/backend/``web/frontend/` 均在 Dockerfile 的 `COPY` 阶段拷进镜像,**没有源码挂载**——改完 Python/Go/Vue 代码不重建镜像就跑等于跑旧代码。这是重要陷阱。
## 配置/密钥规则
`.gitignore` 排除范围广(见文件):`data/``*.db*``.env*`、CTP 流文件(`*.con`/`*.dat`/`ResultInfo.xml` 等)、`.claude/`、所有日志。新增任何账户、token、行情流文件务必先确认匹配 ignore 规则。
注意 `web/backend/dist/``.gitignore` 中有显式例外:目录本身入库,但内部文件除 `.gitkeep`/`index.html` 外都被忽略——这是为了 `go:embed all:dist` 在本地能编译,真正的 SPA 产物在 Docker 构建期生成。
## Web 模块(报告浏览端)
`./web/` 是独立的报告浏览端,与 `tushare` 流水线解耦:tushare 写 PostgreSQL,web 读写 PostgreSQL(业务数据 + 用户表)。docker-compose 上是 `web` 服务,与 `tushare`/`postgres` 共存不互相依赖。
**架构与边界**:
- 后端 Go(`golang:1.25.8-alpine3.23` 构建,`alpine:3.23` 运行),路由 `chi`,数据库驱动 `github.com/lib/pq`(PostgreSQL),业务数据与用户鉴权统一由 PostgreSQL 管理。前端 Vue 3 + Vite + Element Plus + ECharts。
- 单进程同源服务:Vue 产物在 Docker 构建期由 `node` 阶段产出 `dist/`,被 `go:embed all:dist` 嵌入二进制,运行时由 Go 同时服务 `/api/*` 与 SPA 静态文件——不引入 nginx 旁车。
- 统一 DB:业务数据与用户鉴权数据均存储在 PostgreSQL `futures` 数据库中,通过 `DATABASE_URL` 访问。`auth.db`(SQLite)已废弃,`users` 表现在由 `AuthStore` 直接管理在 PostgreSQL 中。
- 鉴权已简化:登录接口返回固定 token,`middleware.RequireUser` 直接注入默认管理员上下文,所有请求放行。后端仍保留密码校验与角色检查(`RequireAdmin`)。前端把 token 持久化到 `localStorage`,axios 拦截器统一注入 + 401 自动跳登录。
- 前端支持暗/浅色模式切换(`stores/theme.ts`),侧边导航在暗色模式用 `#282828`、浅色模式用 `#f9fafb`
**禁止公开注册**:登录后管理员才能在 `/admin/users` 维护账号。首次启动时 `auth.Bootstrap` 检查 `users` 表,若没有 admin 行,则自动创建默认管理员 `admin` / `admin`,并标记强制首次登录后改密码。忘记管理员密码的恢复方式:停服 → 清理 PostgreSQL 中的 admin 记录 → 重启。
**鉴权已简化**:当前 `middleware.RequireUser` 直接注入默认管理员用户到上下文,所有请求放行;`handlers.Login` 返回固定 token (`"noop"`),不再使用 JWT。后端仍保留登录校验密码和角色检查(`RequireAdmin`),但 token 本身已不做签名验证。前端保持原有登录流程和 localStorage token 持久化不变。
**修改即重建**:沿用 `tushare` 服务的约定,`web/backend/``web/frontend/` 都通过镜像 COPY 进容器,**没有源码挂载**。改完 Go/Vue 代码不重建镜像就跑等于跑旧代码。重建命令 `docker-compose -f docker-compose.trade.yml build web`
**常用命令**:
```bash
# 启动 web 服务
docker-compose -f docker-compose.trade.yml up -d web
docker-compose -f docker-compose.trade.yml logs -f web # 看 [bootstrap] 日志确认 admin 是否被创建
# 仅重建 web,不影响 tushare
docker-compose -f docker-compose.trade.yml build web && docker-compose -f docker-compose.trade.yml up -d web
# 本地开发 (后端 + 前端分别起,api 走代理)
cd web/backend && go run ./ # 需要本地 Go 1.25.8;dist/ 目录的占位会被 embed
cd web/frontend && npm install && npm run dev # 默认 5173 端口,/api 代理到 4000
```