Files
trade/CLAUDE.md
2026-05-04 23:27:45 +08:00

95 lines
7.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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``/api/v1/admin/reset-data`(清空行情数据) 等端点。启动时自动 `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)) × 波动率惩罚系数。短期引入幅度因子(价格/OI变化率)和量能确认,按象限(增仓涨/跌、减仓涨/跌、持平)给基础分再叠加加成;中期资金意愿连续化(50 + (增仓涨-增仓跌)/15×50);长期加入30日价格趋势分与OI趋势分 4:6 合成;高波动品种综合分打 85-100 折。`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
```