249 lines
22 KiB
Markdown
249 lines
22 KiB
Markdown
# WorldQuant Alpha 研究工作空间
|
||
|
||
个人单账户系统,提供平台资料、Alpha 分组同步与查询、PnL 缓存、本地自相关检测、本地研究记录、数据目录、AI 助手及通用回测。回测支持 REGULAR + FASTEXPR;不触发平台检查、不回写属性、不正式提交 Alpha。
|
||
|
||
需求与后续路线图见 [项目方案](docs/project-plan.md),AI 助手范围见 [开发计划](docs/ai-chatbot-plan.md)。前端 React 19 + TypeScript + Semi Design,后端 Python 3.12 + FastAPI + HTTPX + SQLAlchemy,PostgreSQL 保存数据,Caddy 提供 Web 入口。前后端独立依赖、独立构建,所有部署文件位于根目录。
|
||
|
||
## 本机启动
|
||
|
||
需要 Docker Engine/Desktop 和 Docker Compose v2;初始化脚本需要 Python 3。项目根目录执行:
|
||
|
||
```bash
|
||
python3 scripts/init_env.py
|
||
docker compose up -d --build --wait
|
||
docker compose ps
|
||
```
|
||
|
||
打开 **http://localhost:8080**。用户名默认 `admin`,初始密码读取本机 `.env` 中的 `ADMIN_PASSWORD`。脚本以仅当前用户可读写的权限创建 `.env`,不会覆盖已有文件或打印密钥。已有 `.env` 时直接启动即可。
|
||
|
||
`web` 仅绑定 `127.0.0.1`;`backend` 和 `db` 没有宿主机端口。使用 `localhost` 访问以匹配请求来源校验。修改端口时更改 `.env` 中的 `LOCAL_PORT` 并重建容器。
|
||
|
||
首次使用:
|
||
|
||
1. 登录系统,在“个人信息”保存 WorldQuant 邮箱和密码,点击“连接 WorldQuant”。
|
||
2. 如平台要求人工验证,在显示的入口完成操作,再点击“继续验证”;后台保留同一挑战会话。
|
||
3. 在“Alpha 管理”切换“待提交 / 已提交”。待提交先选创建日期范围,按天同步;已提交可选提交日期范围按天同步,或全量同步。相同起止日期表示单日,日期边界为 UTC,均包含隐藏记录。也可导入指定 Alpha ID。任务面板显示当前日期、进度、错误、取消和重试。
|
||
4. 点击 Alpha 打开详情。研究记录保存在本地;PnL 点击获取后缓存。详情的“本地自相关”可发起检测,列表也可选中最多 100 条批量检测。建议先全量同步已提交 Alpha,建立比较基准。下次同步会更新平台数据并保留本地研究记录。
|
||
|
||
本地自相关只与本地已同步、同地区的已提交 Alpha 比较,排除自身。使用累计 PnL 的日变化,在目标最新数据日往前四年的共同窗口计算 Pearson 相关系数,至少需要 30 个共同有效样本;带符号最大值达到 0.7 时提示相关性偏高。这是本地规则,不等同于平台检查。PnL 缓存缺失时自动补取;样本不足、常量序列和不可用基准会明确显示,不能当作通过。结果独立保存,相关 PnL、地区或基准成员变化后标记为“待重算”。
|
||
|
||
平台未返回的资料与指标保留为空。数值筛选采用平台原始单位,例如 Turnover `0.15` 表示 15%。日期筛选边界为 UTC;时间显示采用个人页的时区偏好。
|
||
|
||
个人信息页展示平台权限、会话有效期、提交与模拟用量;已配置账户的连接表单默认收起,通过“连接设置”展开。回测每日 `10,000` 次是本地设定的展示额度,按美东日期的活动次数计算剩余次数,并非平台返回的配额。当日记录缺失时显示未知,不把剩余次数估算为满额。点击“刷新资料”更新这些快照。
|
||
|
||
工作空间和 AI 交互统一采用紧凑的 Lark 样式。Alpha 列表只滚动表体,分页保持在可用区域底部;个人信息页独立滚动。
|
||
|
||
## 数据集与数据字段
|
||
|
||
从侧栏进入“数据集”,设置 Region、Universe、Delay 后手动同步目录。范围选项表示本版支持的组合,平台账户实际权限以同步结果为准;分类和子分类来自已同步数据。
|
||
|
||
选中一个数据集后默认使用整集字段;首次使用先同步全部字段。字段列表、搜索、类型、覆盖率、排序及翻页均不改变输入范围,只有明确取消勾选才排除字段。表头选择作用于整个已完成集合,支持恢复全选。字段与详情采用 75% / 30% 的工作区右抽屉,窄屏展开为全宽;逐层关闭保留父层条件。抽屉顶部可打开 AI 助手,业务抽屉暂时隐藏,收起助手后恢复;发送消息时会附带当前范围和输入引用;助手可通过工具读取本地目录和字段,不发送未保存的研究备注。
|
||
|
||
“用于 Alpha 模板”先保存输入草稿,在服务端固定数据集、研究范围、集合版本、字段 ID 和字段类型。点击“用此输入研究”将该快照带入聊天;也可从“已保存输入”恢复。后续同步不会改变旧草稿。
|
||
|
||
数据集和字段备注单独保存,版本冲突保留当前草稿。字段同步沿用已有任务面板的进度、取消、重试、等待连接和人工验证;每页与检查点同事务保存。只有完整分页成功才发布新集合,失败或取消继续使用上一版;首次未完成时不可准备输入。异常字段归属、覆盖率单位或分页协议会失败,不以部分字段代替全集。
|
||
|
||
增量迁移 `0003` 只增加目录、集合、备注与输入表,不改写旧迁移。`/api/v1/catalog` 提供带会话和来源校验的目录/字段查询、完整集合成员、备注、同步创建和输入草稿接口;创建目录同步返回任务 ID,查询、取消及重试仍使用 `/api/v1/sync-jobs`。新任务 `payload` 显式记录范围及数据集,保留旧 Alpha 任务契约。
|
||
|
||
真实 WorldQuant 数据集 schema、字段所属数据集信息、0–1 覆盖率单位、范围权限和分页协议尚需只读联调。当前证据来自 HTTP 边界合成数据和隔离 PostgreSQL,不代表已验证真实平台兼容性。
|
||
|
||
## AI 研究助手
|
||
|
||
1. 在“个人信息 → 大模型服务”填写 Base URL、API Key、模型标识,明确选择 Chat Completions 或 Responses。
|
||
2. Base URL 是后端能够访问的 API 根地址,例如 `https://供应商域名/v1`,是否带 `/v1` 以供应商说明为准;无需拼接 `/chat/completions` 或 `/responses`。容器中的 `localhost` 指容器自身。
|
||
3. 保存配置不会发起模型请求。点击“测试连接”后,系统用少量合成文本和无副作用工具分别测试回答、流式输出、工具往返;测试可能按供应商规则计费。
|
||
4. 全部通过后勾选“启用研究助手”并保存。更换地址、模型、协议或密钥后必须重新测试;更换地址必须重填密钥。
|
||
5. 点击右下角“AI 研究助手”或顶部“AI 助手”,新建会话开始使用。可以询问当前 Alpha、筛选换手率不超过 15% 的记录、查看缓存 PnL,或提出研究记录修改和同步任务操作。
|
||
|
||
聊天默认收起,展开宽度为 420px,左边缘可拖动或用左右方向键调整到 360–640px。宽屏聊天与详情并排;窄屏打开聊天时暂时隐藏详情和任务面板,并通过遮罩隔离背景操作,收起后恢复。点击遮罩、收起按钮或按 Esc 可收起聊天。页面切换保留当前聊天、筛选和研究草稿,草稿内容不会自动发送给模型。
|
||
|
||
本地研究修改、批量标签/状态、创建/取消/重试同步任务均先显示预览。只有点击“确认执行”才会写入;文字中的同意不能替代按钮。预览固定目标及版本,批量最多 100 条。页面与 AI 同时编辑出现冲突时不会覆盖新版本;复制需要保留的草稿后载入最新记录再编辑。任务进度沿用业务轮询;停止聊天不会取消已创建的同步任务。
|
||
|
||
面板收起、切换会话和网络断开不会停止后端执行。刷新后从服务端历史与快照恢复,活动执行每 3 秒更新;不提供逐 token 续传。“停止生成”请求后端取消,再关闭前端接收。服务重启会将生成中的轮次标记为中断,不自动重放;待确认记录在重新登录后仍可处理,但重新检查版本。模型配置变更后,旧的待确认轮次需停止并重新预览。
|
||
|
||
模型不可用或未配置时,原有业务功能继续使用。API Key 仅加密存储于数据库,不返回浏览器;发送聊天时,相关本地业务结果会发送至你指定的模型服务。没有 MCP、知识检索、多 Agent 或平台属性回写。回测使用独立的固定集合确认,详见下文。
|
||
|
||
## Chatbox 研究到回测结果
|
||
|
||
可以从保存的数据输入点击“用此输入研究”,或直接在聊天中指定研究范围,让助手选择已同步的数据集与字段。例如:“用此输入构建一个基本面排序 Alpha,解释字段和假设,预览回测。”助手通过固定输入、具名字段绑定和明确模拟参数构建候选;预览显示表达式及研究来源,点击“确认执行”后启动回测。
|
||
|
||
回测完成后可在同一会话追问“查看刚才回测的结果并解释指标”,也可打开回测详情。Alpha 管理中的“研究来源”页签可查看关联回测、原聊天和输入快照;列表支持按来源筛选。同一 Alpha 的多次研究分别保留,不覆盖本地研究备注。完成回测不会自动唤醒模型。
|
||
|
||
Chatbox 来源使用 `kind=chatbox`,会话 ID 为 `reference`,生成轮次 ID 为 `research_id`,由服务端赋值;既有草稿、裁剪和重跑保留原生成来源。字段绑定检查输入归属、类型和范围,不代替 FASTEXPR 语义或平台算子权限验证,不自动加入 VECTOR 聚合或清洗操作。接口与验证范围见 [集成规格](.scratch/chatbox-research/spec.md)。
|
||
|
||
## 通用回测
|
||
|
||
在“回测”页录入表达式及明确参数,保存候选草稿或直接预览;支持逐项 JSON 输入。预览固定完整集合,显示分组、分批和历史重复提示;排除候选会生成新预览。确认启动立即返回运行,后台负责执行及收集。AI 使用同一预览与启动契约,每次运行确认一次;关闭聊天不终止回测。
|
||
|
||
默认本地并发 3、每批最多 8 条,可在页面调整;并发影响后续补位,批大小在预览时固定。这是本系统调度配置,不是平台已验证额度。各研究来源轮转共享账户预算,同步仍能独立执行。
|
||
|
||
暂停阻止尚未进入提交阶段的批次,停止把这些剩余项标为跳过;已经持久化提交意图的执行可能已发出,继续收集结果。详情失败通过“找回结果”补取原模拟;明确失败项通过新预览重跑。提交结果未知时不会自动重提,在执行记录中补入同一平台的原模拟 URL 后核对。无引用的未知执行保守占用预算。
|
||
|
||
结果保存独立历史快照,后续同步不改写;缺失指标保持 null。基础页面不依赖模型。迁移 `0004` 新增回测表,保留已有数据。备份需包括草稿、预览、运行、执行尝试、结果和增量事件;恢复优先查询已知平台引用。
|
||
|
||
公共接口位于 `/api/v1/backtests`,对接与验证记录见 [实施规格](.scratch/backtest/spec.md) 和 [回测验收记录](.scratch/backtest/verification.md)。真实平台权限、当前协议与限额尚未联调。
|
||
|
||
## 公网 HTTPS 部署
|
||
|
||
`compose.public.yaml` 是独立配置,不与本机配置叠加。先在服务器完成上面的密钥初始化,将 `.env` 中 `DOMAIN` 改为自己的域名(无协议、路径、端口)。DNS 指向服务器,允许入站 TCP 80/443,UDP 443 可选。
|
||
|
||
```bash
|
||
docker compose -f compose.public.yaml up -d --build --wait
|
||
docker compose -f compose.public.yaml logs --tail=100 web
|
||
```
|
||
|
||
访问 `https://你的域名`。Caddy 自动签发/续期证书并重定向 HTTP;后端固定启用 `Secure`、`HttpOnly`、`SameSite=Strict` 的服务端会话 Cookie,并校验写请求来源。无开放注册。数据库仅在 Compose 网络中可见。证书持久化到 `caddy_data` 卷。
|
||
|
||
不要使用示例域名申请证书。公网证书签发取决于实际 DNS、服务器网络与 ACME 服务;本地测试不能代替真实域名的 HTTPS 验收。生产环境请保持单个 backend 容器、单个 Uvicorn worker;首期任务执行不支持多副本。
|
||
|
||
## 配置与账户安全
|
||
|
||
| 配置 | 用途 |
|
||
| --- | --- |
|
||
| `ADMIN_USERNAME` / `ADMIN_PASSWORD` | 仅首次空库初始化管理员,重启不会重置现有密码 |
|
||
| `POSTGRES_PASSWORD` | 数据库密码;初始化脚本使用随机十六进制,避免连接 URL 转义问题 |
|
||
| `ENCRYPTION_KEY` | 独立 Fernet 密钥,加密数据库中的 WorldQuant 密码和模型 API Key |
|
||
| `LOCAL_PORT` | 本机入口端口,默认 8080 |
|
||
| `DOMAIN` | 公网域名 |
|
||
| `AI_REQUEST_LIMIT` | 每轮模型请求上限,默认 12 |
|
||
| `AI_TOOL_LIMIT` | 每轮工具执行上限,默认 12 |
|
||
| `AI_OUTPUT_TOKENS` | 每次模型输出上限,默认 4096 |
|
||
| `AI_TIMEOUT` | 每轮累计活动执行时限(秒),默认 180,等待确认不计入 |
|
||
|
||
WorldQuant 密码仅在后端解密。平台 Cookie 仅保存在后端内存,进程重启后重新认证。前端不保存密码或 Cookie 副本;日志与响应不输出平台认证正文。`.env` 不进入 Docker 构建上下文,应与数据库备份分别安全保管。丢失 `ENCRYPTION_KEY` 后须重新输入平台密码和模型 API Key;切勿在正常升级时重新生成它。
|
||
|
||
修改系统密码(同时撤销所有系统会话):
|
||
|
||
```bash
|
||
docker compose exec backend python -m app.cli reset-password
|
||
```
|
||
|
||
公网时为命令补上 `-f compose.public.yaml`。单账户一旦同步确认身份,不允许更换邮箱混入其他账户数据。断开平台连接会暂停未完成任务;重新连接并确认身份后恢复。
|
||
|
||
## 升级与数据库迁移
|
||
|
||
依赖锁文件分别是 `backend/uv.lock` 和 `frontend/pnpm-lock.yaml`。每次后端启动都会执行 `alembic upgrade head`,失败时不会启动 API。升级前先备份数据库与 `.env`,然后:
|
||
|
||
```bash
|
||
docker compose up -d --build --wait
|
||
docker compose exec backend alembic current
|
||
docker compose logs --tail=100 backend
|
||
```
|
||
|
||
普通 `docker compose down` 不删除数据卷,重建后数据保留。**`down -v` 会删除数据库与证书卷,正常停机/升级不要使用。**
|
||
|
||
新建迁移的开发命令为 `uv run alembic revision --autogenerate -m "说明"`;须人工审阅生成文件,再运行 `uv run alembic upgrade head` 和测试。已发布的迁移文件保持不变。
|
||
|
||
## 备份与恢复
|
||
|
||
以下为本机配置命令;公网统一补上 `-f compose.public.yaml`,自定义项目名时保持相同 `-p`。数据库备份包括平台快照、研究记录及版本、本地自相关结果、账户密文、模型配置密文、AI 会话/消息/执行/工具确认记录和同步任务。备份文件仍属于私有数据。
|
||
|
||
```bash
|
||
mkdir -p backups
|
||
umask 077
|
||
docker compose exec -T db pg_dump -U wq -d wq -Fc --no-owner > backups/wq.dump
|
||
```
|
||
|
||
先恢复到独立数据库校验,不覆盖正在使用的数据:
|
||
|
||
```bash
|
||
docker compose exec -T db createdb -U wq wq_restore_check
|
||
docker compose exec -T db pg_restore -U wq -d wq_restore_check --no-owner --exit-on-error < backups/wq.dump
|
||
docker compose exec -T db psql -U wq -d wq_restore_check -c 'SELECT count(*) FROM alphas; SELECT count(*) FROM research;'
|
||
```
|
||
|
||
确认备份正确后,若需要恢复正式库,下面操作会覆盖现有库内容,应先另做当前备份并停止写入:
|
||
|
||
```bash
|
||
docker compose stop web backend
|
||
docker compose exec -T db pg_restore -U wq -d wq --clean --if-exists --no-owner --exit-on-error < backups/wq.dump
|
||
docker compose up -d --wait
|
||
```
|
||
|
||
跨机器恢复时同时使用原来的 `ENCRYPTION_KEY`。恢复后运行中的同步任务自动回到队列,按已提交检查点继续;平台会话可能要求重新连接或人工验证。
|
||
|
||
## 本地开发与验证
|
||
|
||
后端使用 `uv` 和 Python 3.12,前端使用 Node 22.12+ 与 pnpm 9.15.0。
|
||
|
||
```bash
|
||
cd backend
|
||
uv sync --python 3.12
|
||
uv run ruff check app tests
|
||
uv run pytest -q
|
||
```
|
||
|
||
自动化测试使用隔离的 SQLite 与 HTTPX 模拟上游,不读取真实凭据或请求 WorldQuant。涵盖 API 鉴权、加密、查询/导出一致性、同步重试与恢复、人工验证、类型差异和 PnL schema。部署验收另用真实 PostgreSQL 和 Docker。
|
||
|
||
```bash
|
||
cd frontend
|
||
corepack enable
|
||
pnpm install --frozen-lockfile
|
||
pnpm build
|
||
pnpm exec playwright install chromium
|
||
pnpm test
|
||
```
|
||
|
||
浏览器测试自动启动临时数据库、模拟平台 API 和 Vite,使用 620 条明确标记 `TEST` 的合成 Alpha。不会向正式数据库写入样例。测试验证模型配置、查询卡片、修改预览及确认、草稿冲突、收起及刷新恢复、取消,以及系统登录、账户连接、双 Tab、按日及全量同步、本地自相关保存、SUPER 详情、备注与收藏保留、PnL、分组 CSV 导出及退出。截图写入忽略目录 `output/playwright/`。
|
||
|
||
需要重跑 Docker 持久化和备份验收时,创建独立测试环境,并在测试 env 文件中选择空闲 `LOCAL_PORT`(例如 18089),无需停止正式实例。以下脚本只接受 `wq-alpha-acceptance*` 项目名:
|
||
|
||
```bash
|
||
mkdir -p .local
|
||
python3 scripts/init_env.py --output .local/docker-test.env
|
||
docker compose --env-file .local/docker-test.env -p wq-alpha-acceptance up -d --build --wait
|
||
python3 backend/tests/docker_acceptance.py --env-file .local/docker-test.env
|
||
# 仅删除上面新建的测试容器和测试卷
|
||
docker compose --env-file .local/docker-test.env -p wq-alpha-acceptance down -v
|
||
```
|
||
|
||
独立启动模拟环境以开发 UI(两个终端):
|
||
|
||
```bash
|
||
# 终端 1,backend/ 下
|
||
uv run uvicorn tests.browser_server:create_test_app --factory --host 127.0.0.1 --port 18000
|
||
# 终端 2,frontend/ 下
|
||
WQ_DEV_API=http://127.0.0.1:18000 pnpm dev --port 5179
|
||
```
|
||
|
||
访问 `http://127.0.0.1:5179`,系统测试密码 `browser-test-password`,平台邮箱 `test@example.com`、密码任意。模型 Base URL 可填 `https://model.test/v1`、模型标识 `test-model`、API Key 任意;该测试服务始终使用确定性的内存模拟模型,不发起模型网络请求。每次停止服务即丢弃临时测试数据。
|
||
|
||
开发真实后端时显式配置 `DATABASE_URL` 指向自己的开发 PostgreSQL,设置 `ADMIN_PASSWORD`、`ENCRYPTION_KEY`、`PUBLIC_ORIGIN=http://localhost:5173`,执行迁移后用 `uv run uvicorn app.main:create_app --factory --host 127.0.0.1 --port 8000` 启动。`pnpm dev` 默认代理到此地址。生产 Compose 不开放开发数据库端口。
|
||
|
||
## 接口与数据约定
|
||
|
||
FastAPI 的 `/openapi.json` 与 `/docs` 可在后端开发端口访问;生产 Web 入口只代理 `/api/*`,不对外公开文档页面。
|
||
|
||
- `/api/v1/auth`:登录、退出、会话;除登录与健康检查外,业务接口都需要 Cookie。
|
||
- `/api/v1/account`:偏好、加密凭据、连接/验证/断开/资料刷新。
|
||
- `/api/v1/alphas`:服务端筛选与排序、详情、本地研究记录、批量编辑、流式 CSV。
|
||
- `/api/v1/alphas/{id}/sources`:分页查看已保存回测的研究来源;Alpha 列表及 CSV 支持 `source`、`source_reference`、`research_id`、`backtest_run_id` 筛选。
|
||
- `/api/v1/alphas/{id}/pnl`:只读缓存;刷新通过 `pnl_refresh` 任务。
|
||
- `/api/v1/alphas/{id}/self-correlation`:读取本地检测结果;检测通过 `self_correlation` 任务。
|
||
- `/api/v1/sync-jobs`:创建任务立即返回 202 和 ID,查询、取消与重试。
|
||
- `/api/v1/backtests`:候选草稿、不可变预览、异步启动、运行/结果/事件分页、调度配置、暂停/继续/停止/找回及重跑预览。
|
||
- `/api/v1/backtests/research-previews`:通过固定输入、表达式模板和字段绑定生成候选预览;沿用现有确认启动接口。
|
||
- `/api/v1/ai`:脱敏模型配置与测试、会话历史、SSE 执行、执行快照、取消及确认。新执行只接收 `request_id`、`message`、`context`;同一会话重复请求 ID 返回原运行,参数变化返回 409。
|
||
|
||
研究记录 PATCH 现在必须提供读取时的 `version`;批量编辑必须提供每个目标 ID 的 `versions` 映射。`0002` 迁移给旧研究记录设置初始版本 1,不修改其内容。版本冲突返回 409。
|
||
|
||
写请求需 `X-WQ-Request: 1`;浏览器跨站写入被拒绝。Alpha 平台快照、`research` 本地研究、`pnl_cache`、`self_correlations` 本地检测结果分开存储。`0005` 迁移只新增检测结果表。研究状态固定为 `inbox/candidate/optimizing/archived`;平台类型、语言、状态按原值显示。
|
||
|
||
列表及导出支持 `submission=UNSUBMITTED|SUBMITTED`,平台状态缺失时不推断为已提交。`daily_sync` 必须提供分组及 `date_from` / `date_to`,每个 UTC 日期分别分页获取可见、隐藏记录;新建 `full_sync` 只同步已提交。旧的无分组全量任务保持原范围恢复。每页数据与检查点同事务提交,Alpha ID 幂等更新。失败任务保留进度,重试只处理剩余页或失败 ID。上游 `Retry-After` 等待可被取消。分页过程中平台记录移动可能造成重复或遗漏,通过 ID 去重和再次同步对应范围校正;单次没有查到不自动删除本地记录。
|
||
|
||
## 日志排查与验证边界
|
||
|
||
```bash
|
||
docker compose ps
|
||
docker compose logs --tail=100 backend
|
||
docker compose logs --tail=100 web
|
||
docker compose logs --tail=100 db
|
||
curl -f http://localhost:8080/api/v1/health
|
||
```
|
||
|
||
平台任务失败时先查看任务面板的错误及失败 ID。401 登录失效需重新登录系统;平台人工验证需回个人页;429 会按平台等待时间自动重试。密钥损坏/丢失时重新配置平台凭据。不要为排错把密码、认证响应或 Cookie 加入日志。
|
||
|
||
AI 模型兼容性由模拟 Chat Completions/Responses HTTP 流与真实 SDK 适配器验证;未配置真实供应商前,不能保证其工具选择质量、模型权限或网关兼容性。真实联调请分别记录流式回答与业务工具调用是否成功。
|
||
|
||
实现参考旧项目请求形态,并对模拟上游做自动化验证。新增日期筛选参数、WorldQuant 当前真实账号权限、人工验证页面行为、实际数据 schema、真实账户同步及公网证书签发,均需要在自己的账户/域名完成只读联调;未取得该证据前不宣称已验证。验收实测结果见 [验收记录](docs/verification.md)。
|