Commit Graph
14 Commits
Author SHA1 Message Date
Simon 36fe018075 docs+chore: 同步操作说明与端到端自检(字段库/单位换算、因子参数化)
- docs/USAGE.md:
  · 因子层一行改为「代码注册表投影 + 参数化实例,参数写在名字里以冻结口径」;
  · 新增 `GET/POST/PATCH /api/factors`、`GET /api/factors/templates` 与
    `/api/condition-fields`、`/fields` 的说明;
  · 新增「参数化因子(2026-10)」块:受控范围、键必须写全参数(缺项就靠可改的
    默认值兜底 = 追溯改义,所以拒绝)、口径文案按代码收敛、停用 ≠ 删除、
    参数化因子也能当过滤条件;
  · 自检清单一并更新(pytest 500 条;verify_strategy_workspace 145 项 skip-job;
    verify_ui_alignment 8 页 160 项;新增 verify_unit_conversion、verify_factor_params)。
- scripts/:新增 verify_unit_conversion.py(单位只能在给定范围里选 + 界面单位⇄
  基准单位换算)、verify_factor_params.py(参数暴露/界面新建/越界拒绝/停用语义,
  跑完自动清掉临时因子);verify_strategy_workspace.py 加 [5.7b] 因子参数化一节,
  临时因子的清理挪进 finally(断言中途失败也不给真人库留垃圾)。
- .gitignore:docs/screenshots/ 是临时验证证据,不入库(文件留在磁盘)。
2026-10-01 16:38:54 +08:00
Simon 50a1030afa fix(web): 参数表单收束 + 一句话说明改多行(按截图实测修两处失调)
用户给了真实截图,指出两处肉眼可见的不协调,逐项定位后修复:

1. 「一句话说明」是单行 input 被塞进 ~360px 的格子,placeholder
   「例:全市场股息率最高的 2」直接截断 —— 内容太多、框太小。
   → 改为整宽多行 <textarea>(rows=2、min-height 64px、可纵向拉伸),
     与定宽 340px 的策略名并排(.params-meta flex),窄屏自动上下堆叠;
     实时字数 (N/300) 已在提示里。

2. 「太多地方没有对齐」的根因:表单铺满 ~1900px 内容区,5 列各 ~360px,
   控件拉得太开;因子下拉用 1fr 撑到 ~1500px 而权重框才 118px,比例失调;
   数字输入还有 max-width:180px 上限,比同行下拉窄一截。
   → .params-form 约束到 ~1100px(每列 ~210px,所有控件按 1fr 等宽,
     左右边缘严格对齐);移除已多余的 max-width:180px(限宽后它反而
     制造新的不等宽),数值/日期改为填满单元格;因子行首列封顶 460px、
     整行限宽 720px,条件行同理(首列 ≤360px、限宽 760px);
     复权口径选项去掉括号里的「股息策略推荐」(已在 hint 说明),不再截断。

验证方式也升级了:这次是**截图后用 read_image 看渲染像素**确认,而不只量几何。
对齐自检同步把 textarea(高度随行数变、本就该比单行高)排除出「同排等高 /
高度归一」比较,并把数字过宽阈值调到 240px(限宽后 ~210px 属正常)。

门禁:tsc 0 错误、图表单测 7/7、next build 成功、页面 200、
对齐自检 140/140、契约自检 59/59;/backtest 与 /strategies 截图复核通过。
2026-09-30 19:56:40 +08:00
Simon 9aaca12751 fix(web): 控件对齐与输入友好整改(控件高度令牌化 + 对齐自检脚本)
问题不是"不好看",而是**可测量的错位**:同一行里原生 date 输入 38.8px、数字输入
36.8px、按钮 34px;16px 的勾选框与 36.8px 的下拉同排;因子行的下拉与权重框没有
可见标签;列表里的勾选框点不中;参数非法时「运行回测」直接置灰且不说原因。

根因:控件高度靠「上下 padding + 行高」拼出来,而 input / select / button 的原生行高
各不相同(Chrome 的 date 还会多 2px),必然参差;加上各处内联像素宽度
(style={{width:220}}、flex:1)与自搓布局,列自然对不齐。

改动:
- 新增控件高度令牌 --ctl-h-sm/md/lg(28/34/38px)与 --ctl-px,.input/select/.btn/
  .icon-btn/date 统一显式 height(不再拼 padding);原生 checkbox/radio 统一 16px,
  点击热区交给外层 label(.check/.radio-row/.check--cell),表格整格可点
- 因子行、选股条件行改为「表头 + CSS 栅格」成列对齐,列宽由样式决定,
  去掉内联像素宽度与 flex 拉伸,配 aria-label 供读屏分辨重复行
- 表单友好化:错误提示改为**失焦或提交后**才出现(清空重填的瞬间不再标红);
  提交被拦下时一次展开全部行内错误 + 自动聚焦并滚动到第一个问题字段;
  运行/保存按钮不再因参数非法而置灰(灰按钮不说原因 = 看起来不可点却无响应),
  改为可点击并讲清原因;补齐 topN/costs 两处「产生了却没人显示」的行内错误落点
- 数值字段补 inputMode/step/min/max 与单位、取值范围提示;工具条检索/筛选用
  .input--search/.input--filter/.input--picker 类,不再写内联宽度
- /experiments 筛选无结果的空态与「暂无实验」区分开(原文案会让人以为归档丢了)
- 同一页面可能挂两份表单:radio name 与 label/for 加表单实例前缀(useId),
  否则两边单选互相取消、label 指错控件
- 新增 scripts/verify_ui_alignment.py:系统 Chrome + 原生 CDP(仅标准库,
  独占随机端口与临时 profile),按 7 个页面 × 1500/375px 检查同排等高、
  高度取值归一、点击目标、标签与无障碍名、字号圆角一致、尺寸匹配内容、
  横向溢出、提示裁切;本次基线 108/32 → 现 140/140

验证:pytest 388 passed、ruff 全绿(顺带清掉 qlib_verify.py 一处死代码)、
tsc 0 错误、图表单测 7 passed、next build 成功、契约自检 59/59、
对齐自检 140/140(含 375px 小屏)。
2026-09-27 09:01:55 +08:00
Simon 82240e383d docs: 同步操作说明/架构/路线图(归档操作、图表基座、数据库目标硬约束)
- USAGE 新增 §6.3.1「归档的日常操作」:查看 / 筛选(回写 URL)/ 导出完整 JSON /
  以此参数再跑 / 删除(写明「删除即失去结果,结果只存归档一份」)/
  历史归档用 restore_experiment_from_job 按原 id 重建;并说明归档完整度如何标注
- USAGE/README 更正技术栈与图表基座:TradingView Lightweight Charts 4.2.3 为唯一
  图表基座(ECharts 已从 package.json、pnpm-lock.yaml、node_modules、文档与
  架构图标注中全部清除),并记录实测证据(个股页图表根节点为
  div.tv-lightweight-charts,页面 canvas 无一来自其它图表库)
- ARCHITECTURE 更正「当前数据库」(原写 SQLite/未来 MySQL):现为本机 MariaDB 10.11,
  §6 补目标库硬约束;USAGE 补服务器身份与实测连接证据
- AGENT.md 新增 §0.1:数据库目标只允许本机 MariaDB,禁止 192.168.1.10,
  由 config.py::assert_db_target_allowed 硬拦截(命中直接抛错,不静默降级)
- DEV_PLAN_DIVIDEND_BACKTEST 记录三轮实施与验证、归档恢复边界(§12.5)、已知限制
- DEV_PLAN v2/v3 标注为历史记录(避免把当时的远端库地址当现状照抄);
  ROADMAP 更正 M3 图表选型
2026-09-20 07:31:20 +08:00
Simon adaf97f6d7 docs: 记录 v3 开发执行状态(M9 + 支撑线 + 延后项) 2026-09-09 07:43:53 +08:00
Simon 314bfc159f docs: 同步 README/USAGE 至 M6–M8(选股系统主线 + MySQL + 新 API/Agent 工具/限制)
- README:架构分层示意(Selection/Signal/Portfolio/Composite Engine)、MySQL 默认配置、
  核心能力表、里程碑 M0–M8
- USAGE:概览模块与页面清单、引擎分层 §6.0、API 表新增 /api/selections /api/signals
  /api/strategies /api/composites、Agent 10 工具、已知限制(M8.4 延后/全市场选股同步耗时)
2026-09-09 06:29:51 +08:00
Simon 0ffd574f30 docs: 下阶段开发计划(架构 v2 落地 M6-M8)+ MySQL 迁移文档同步
- docs/DEV_PLAN_v2.md:基于 ARCHITECTURE_v2 与 M0-M5 现状的下一阶段计划
  (M-DB 迁移收尾 → M6 因子定义入库/复合因子/口径修复 → M7 Selection/Signal/
  Portfolio 引擎分层 → M8 Strategy 平台化/Web 做实/Agent 工具补齐;含本机 Redis
  127.0.0.1:6379 的接入触发点与执行顺序)
- ROADMAP.md:登记 M-DB 里程碑并指向 DEV_PLAN_v2
- USAGE.md / README.md:数据库描述由 SQLite 更新为 MySQL(config.yaml database.mysql)
2026-09-08 23:58:51 +08:00
Simon 442999f701 feat(data): 财务/日线同步增量 + 新浪「两边一致」校验兜底 + 逐只进度
- financial 默认增量:按 A 股披露节奏判断已最新并跳过;--full 强制全量重拉
- Tushare fina_indicator 增加报告期窗口与 100 条/请求自动分页(修复老报告期静默截断)
- 新浪兜底收紧为校验兜底:两源重叠历史一致才导入缺失键,行标记 source=sina;
  财务可比字段取 eps/销售毛利率(ROE 两端口径不同不作依据),日线只比较最近重叠交易日
- CLI 输出逐只进度与导入内容描述(来源/行数/报告期与公告区间),失败股票留待重跑
- financial_indicator 增 source 列(迁移 d3f6c9a21b04);新增一致性/分页/服务测试
2026-09-08 21:48:09 +08:00
Simon 55b684fbe1 feat(scripts): dev.sh 前后端一键 start/stop/restart/status/logs
- 启动后端 uvicorn(:8000, --reload, 0.0.0.0) + 前端 next dev(:3000),setsid 独立进程组
- 停止按 pidfile + 监听端口双定位,整进程组清理(无子进程残留,实测残留 0)
- 端口探测 ss 优先(lsof 在该环境对 socket 不可靠)
- status/logs/restart;支持 API_PORT/WEB_PORT/BACKEND_API_URL 覆盖
- 日志落 logs/,pid 落 .run/(均已 gitignore);USAGE §5 增加用法
2026-09-07 20:13:39 +08:00
Simon b78852f01b fix: 前端同源代理 /api → 后端(任意 IP 访问不再 NetworkError)+ SQLite 写锁等待
- 根因①:页面硬编码 http://127.0.0.1:8000/api,从 192.168.1.160:3000 访问时浏览器请求自身/跨域失败
- 根因②(500):全市场数据同步(长写事务)持有 SQLite 锁导致读接口 database is locked
- 前端:next.config.ts rewrites /api/* → http://127.0.0.1:8000/api(BACKEND_API_URL 可覆盖);
  lib/api.ts 默认相对 /api 同源(NEXT_PUBLIC_API_BASE 保留为直连覆盖项);.env.local.example 说明两种方式
- 后端:CORS 开发期 allow_origins=["*"](无凭据,上线前收紧);SQLite engine busy_timeout=30s
- USAGE FAQ 同步;验证:192.168.1.160:3000/api/health 与 /api/factors 经代理 200,CORS 头 access-control-allow-origin: *
2026-09-06 19:00:49 +08:00
Simon fc12ba89ad docs(USAGE): 更新至 QlibEngine v1 / Parquet 导出后的最新状态
- 适用版本 HEAD、技术栈(pyarrow/pyqlib/LightGBM)
- 新增 §6.1 双引擎说明(LocalEngine 默认 / QlibEngine v1 切换与 float32 差异)
- 补 export 命令、API 端点(health/stocks/{symbol})、引擎与 Parquet 相关 FAQ
- 测试计数与覆盖清单更新(86 passed)
- 限制与说明同步(QlibEngine init 幂等、Alpha158+LightGBM 仍为 TODO)
2026-09-06 18:23:37 +08:00
Simon bbb5c1ea52 feat(cli): sync export — 日线按年导出 Parquet(data/parquet/stock_daily/<year>.parquet)
- 对应 ROADMAP §1.4「历史时序大数据转 Parquet」;pyarrow 随 qlib 依赖已可用
- 用法:uv run python -m app.cli.sync export [--years 2023,2024]
- 实测:9680 行 → 2023/2024 两个 parquet(data/parquet 已被 gitignore)
- ruff clean / pytest 86 passed
2026-09-06 18:21:55 +08:00
Simon b8f67f99ae feat(quant): QlibEngine v1 — 本地行情落盘 QlibDataset → D.features 读取 → 因子回测
- qlib_adapter/provider.py:SQLite 行情按 qlib 0.9.8 二进制格式落盘(起始索引头 + 逐日 float32、instruments 3 列、小写 instrument、晚上市 offset)
- qlib_adapter/dataset.py:qlib.init 幂等({'day': uri})+ D.features 读取 close 面板
- qlib_adapter/engine.py:QlibEngine(QuantEngine)v1 —— Qlib 数据管线回测与 LocalEngine 同记账规则(无未来函数/成本/涨跌停标注),factor_test 复用共享实现;Alpha158+LightGBM 为 TODO
- 真实 20 股验证:qlib 落盘 142 文件→读取→回测(-12.81%,Local 对照 -12.97%,差异为 qlib float32 存储)
- tests/test_qlib_engine.py 5 项(格式/roundtrip/晚上市 offset/回测/因子测试)→ pytest 86 passed / ruff clean
2026-09-06 18:20:28 +08:00
Simon 01d818e12a docs: 使用说明 docs/USAGE.md;LLM URL/模型名配置移到 config.yaml(.env 仅 Key)
- config.yaml 新增 agent.llm:base_url / model 明文配置(默认百炼兼容端点 qwen-plus),api_key 只从 .env 的 LLM_API_KEY 读取;LLM_BASE_URL / LLM_MODEL 仍可经 .env 覆盖
- .env.example 注释同步;core.config 读取逻辑 env > yaml > 默认
- docs/USAGE.md:安装/配置/数据同步/启动/研究 API 与 Job/Experiment/Agent/测试门禁/已知限制/FAQ
- README 增加使用说明入口
- 新增 config LLM 测试 2 项(yaml 默认 + env 覆盖)→ pytest 81 passed / ruff clean
2026-09-06 17:57:15 +08:00