Commit Graph
1196 Commits
Author SHA1 Message Date
shy3130 cb046edebb chore(backend): uv.lock 项目版本号同步 0.3.19 (发版时 uv sync 刷新的遗留) 2026-10-28 09:39:50 +08:00
shy3130 c2c4e41463 fix(desktop): 开启 pywebview 文件下载 — 备份导出等 <a download> 点击无反应
pywebview 5.0 起默认取消所有文件下载 (Edge WebView2 args.Cancel / WKWebView 不放行 download 策略), 桌面版里配置备份导出、分析菜单导出、回测/台账 CSV 等 <a download> 直链点击后无声无息。在 webview.start() 前显式设置 ALLOW_DOWNLOADS=True; 必须在 start() 前设置否则部分后端不生效, 回归测试以伪造 webview 模块锁定该顺序。浏览器/Docker 部署不受影响。
2026-10-28 09:39:50 +08:00
shy3130 1cb9c7c69c fix(ci): 日志停用测试适配 Python 3.12.9+ 空文件不滚动 (gh-116263)
CI (Python 3.12) 挂在本机 (3.11) 通过的用例上: gh-116263 给 shouldRollover 加了「空文件永不滚动」守卫, 新 attach 的 handler 指向空文件时首条日志不触发滚动, rotate/handleError 根本不执行。测试预置 100 字节内容使首条日志即滚动, 3.11/3.12 双版本验证通过。产品代码不受影响 (生产滚动时文件必然非空)。
2026-10-28 08:15:47 +08:00
shy3130 88141def9a fix(logs): Windows 日志文件被占用时滚动降级 — 不再逐条刷 WinError 32 堆栈
用户实测: 残留 backend 进程/编辑器握着 backend.log 时, RotatingFileHandler 的 os.rename 抛 PermissionError [WinError 32], logging 默认 handleError 每条日志打一次完整堆栈, 终端刷屏且期间文件日志全部丢失 (业务探测本身全部成功)。
- StallSafeRotatingFileHandler 两级降级: rename 失败 → copy-and-truncate (清自己句柄不需要 DELETE 访问权, 不受他人读句柄影响, 滚动照常完成); 降级后仍连续失败 → 单条带指引的 ERROR 后从 root 摘除关闭, 终端 StreamHandler 不受影响
- 递归防护: 停用流程中自身告警再触发失败直接吞, 不绕回 handleError
- backend.log 与桌面版 desktop.log 共用 attach_rotating_log, 双路径同时受益; 测试 6/6 (2 新增)
2026-10-27 22:54:57 +08:00
shy3130 81611cefac feat(ui): 轮动图四项改版 — 全天时间轴/并排布局/图例换行/配色统一 (#518)
- 盘中时间轴铺全天 09:30–15:00 (桶起点逐格对齐: 上午止于 11:25、下午含 15:00, 并集兜底), 数据止于当前桶右侧留白, 一眼看进度; 1 分钟桶最近 60 列滑动窗口不铺; 两图指针联动轴窗口一致; showMaxLabel 保证 15:00 末刻度可见
- 宽屏改左右并排: 走势图 aspect 9:5 随列宽 (此前全宽 4.4:1 压扁), 右列=切换图+榜单; 右列内层 xl 下绝对定位脱离行高计算, 榜单列内滚动两列底齐; 窄屏退回堆叠
- 图例 scroll→plain + width 94% 自动换行, 不再「◀1/2▶」翻页
- 配色: 调色板去掉两组近绿/三组琥珀/蓝青近似对; colorForSector 按板块名稳定分配并缓存 — 走势线/易主圆点/切换图标注/榜单圆点四点同源, 切排序不漂; 切换图易主标注走 markPoint (强 8px/弱 5px), 函数式 formatter (字符串会让 markPoint 不渲染)
- 开局领涨也算事件点 (原从 index 1 起算, 开盘即领涨的板块整段无标记); 标签像素级 AABB 碰撞避让 (密集簇隐藏后到标签只留圆点, 最强大点优先占位); 圆点底色描边贴线可辨; 榜单未进矩阵板块给灰色占位点
- 测试 13/13 (6 新增: 刻度边界/并集/稳定配色/铺轴 null 对齐/markPoint 语义/开局事件)
2026-10-27 22:54:49 +08:00
shy3130 dc9badc2ff fix(ui): AI 助手悬浮球开关跨端口持久化 — 不再「关了过一会又开」
- 根因: 开关只存 localStorage 且默认开启; 桌面版 _find_free_port 换端口即换 origin, 旧值读不到 → 闪回默认开 (uiPrefs 基建正是为此而生, 该键此前漏接)
- assistant.fab.enabled 入 uiPrefs SPECS + 后端 _UI_PREFS_KEYS 白名单 (assistant_fab_enabled), setFabVisible 走 setUiPref 本地+后端双写
- hydrateUiPrefs 改共享 Promise 的幂等实现: main.tsx 与后进的 assistant store 无论先后, await 到的都是同一次回填; 回填完成后刷新 store 内存态
- 依赖方向保持 扩展→核心, 核心零依赖扩展; 新增白名单回归测试锁住该键
2026-10-27 21:07:29 +08:00
shy3130 b7549521b3 fix(ci): sync_versions.py 在 Windows runner (cp1252 stdout) 崩溃
- 中文 print 撞 cp1252 编码 UnicodeEncodeError, v0.3.19 首次发版 Windows 作业死在同步版本号步骤 (文件写入本身都是 UTF-8 无恙)
- 入口处 stdout/stderr 统一 reconfigure UTF-8 + errors=replace, 本地 PYTHONIOENCODING=cp1252 复现验证通过
2026-10-27 18:53:30 +08:00
shy3130 a214555d6b feat(position): 回测引擎接入仓位策略 (矩阵/legacy 双路径)
- _apply_position_policy: compute 抛错或输出非法时当日回退等权 + scale=1, 计入 execution_stats; normalize_result 强校验不静默放行
- 买入预算乘 budget_scale; recent_returns 窗口严格截止到入场信号日, 成交日K线不进决策 (防未来数据)
- 本文件同时补提 #517 的引擎级 expected_generation 读 attempts 1→2 (load_panel 重试轮改读现役世代), 与 30021462 服务级重试配套
v0.3.19
2026-10-27 18:45:40 +08:00
shy3130 568a0d69ef chore(release): v0.3.19 版本号同步 (package.json 单源派生) 2026-10-27 18:45:27 +08:00
shy3130 4d42fc6b14 docs: 补充策略包/仓位策略/模拟盘绑定即评估的能力说明 2026-10-27 18:45:27 +08:00
shy3130 285dd9b701 fix(data): #514 symbol 级判坏 + 精确修复 + 后置校验 + 自动修复退避
- 判坏改 symbol 级: 盘中快照行中 symbol 同分区无权威行才算缺陷 (两者兼有=无害残留); IntegrityIssue.symbols 带出坏票清单; 旧比例兜底保留, 37 个锁定用例全绿
- 修复只拉坏 symbol (override_symbols 链路: boot 自检/实时 gate/数据修正), 不再一只坏票全市场重拉; 单票失败 failed_out 上浮 stage_errors
- 修复分支末尾重扫覆盖日, 仍有 issue 则任务如实 failed
- 自动修复退避 .integrity_repair_backoff.json (6h): 期内 boot/gate 跳过, gate 409 指向手动修正; 数据页手动修正不受限
2026-10-27 18:45:17 +08:00
shy3130 eb66afb8ee fix(ops): #516 内存可观测 + 两道上限
- /health 追加 memory 块: 进程 RSS / virtual_memory total/available/percent / cgroup v2 current/high/max/events
- worker 轮询 (2s 节流) 监控子进程 RSS, 超 TICK_WORKER_RSS_LIMIT_BYTES (默认 6GiB, 0 关闭) terminate + 明确中文错误; 不用 RLIMIT_AS (polars/numpy 虚拟内存远大于 RSS 会误杀)
- 重任务准入: 系统可用内存低于 TICK_HEAVY_MIN_AVAILABLE_BYTES (默认 1GiB, 0 关闭) 时 FIFO 继续等待
- README 补两个环境变量说明
2026-10-27 18:45:17 +08:00
shy3130 5578cb0182 fix(provider): #515 TdxQuant Key 失效鉴权熔断 — 不再全市场盲试
- 增量/修复轮连续 10 只「返回空数据」→ 置熔断, 冷却 15 分钟内快速失败返回空 df + 单条 ERROR 指引重存 Key; 不再对数千只逐只盲试 (stdout 刷屏随之停止)
- 逐只 warning 改计数, 轮末单条汇总 (失败数/首个错误); 设置页重存 Key 触发 load_all 重建实例, 熔断态自动清零
2026-10-27 18:45:09 +08:00
shy3130 3002146223 fix(backtest): #517 盘中快照读失败 — 有界重试 + 400 指引
- factor run/run_batch 服务级重试 _SNAPSHOT_MAX_ATTEMPTS=3: 撞 EnrichedGenerationUnavailableError (盘中实时刷新换世代) sleep 1s 后重读新世代整体重跑, 耗尽原样上抛
- /factor/run、/factor/batch API 层捕获映射 400「行情数据正在更新(盘中实时刷新), 请稍后重试」(对齐 mining 既有模式), 不再裸 500
2026-10-27 18:45:09 +08:00
shy3130 1c1a3b44c9 fix(release): #513 版本号单源 — 从 frontend/package.json 派生
- 新增 scripts/sync_versions.py: VERSION / backend/pyproject.toml / _FALLBACK_VERSION 三处伴生标记由 package.json 派生, --check 供 CI/本地校验
- release.yml / docker.yml 构建前先跑同步脚本, 杜绝只改 package.json 时产物版本漂移
- Dockerfile 运行时改读 /app/frontend/package.json
2026-10-27 18:45:09 +08:00
shy3130 6d1c6cedc4 feat(paper): 模拟盘「绑定即评估」— 无需另建监控规则
- 账户绑定策略 (自动跟单 match_kind=strategy) 即自动进入实时评估循环: paper_watch 向引擎注入合成规则 paper_watch:{strategy_id} (不落盘/不进监控页), 事件照常喂 paper_auto.on_rule_events
- 同步幂等且与真监控规则去重 (同策略已有启用监控规则则不注入, 避免重复事件); set_rules 是全量覆盖 → 监控规则任何保存后都重注入
- 合成规则信号只驱动模拟盘下单, 不进 SSE 告警/系统通知/webhook/留痕 (quote_service 按 is_paper_watch_event 分流)
- main.py 同时注册 position_policies 路由 (上一提交的 API 入口)
2026-10-27 18:45:02 +08:00
shy3130 e71ca39b25 feat(bundle): 策略包导出/导入 — 依赖闭包一键迁移
- 导出: 策略设置「导出策略包」(.zip), 按依赖闭包打包策略源码 + 引用的自定义信号/因子定义 + 用户调参; 叠加策略递归展开子策略与 overrides
- StrategyDef 增 scoring_columns, meta.scoring / module SCORING 引用列进入闭包
- 导入: 策略池「导入策略」同时接受 .py 与 .zip; 条目路径与配置备份白名单形态一致, 复用 apply_archive 安全校验/导入即冒烟/热重载; 包外路径 400 拒绝; 缺失依赖预览黄色预警
- API: GET /api/strategies/{id}/bundle, POST /api/strategies/bundle/inspect|apply
- engine.py 同时携带 #517 的 expected_generation 读 attempts 1→2 (服务级重试见后续 fix 提交)
2026-10-27 18:44:51 +08:00
shy3130 a402b93fc8 feat(position): 仓位策略 — 用户自定义资金分配规则
- 新增 PositionSizingPolicy: data/user_data/position_policies/*.py, 设置→定义→仓位策略 创建 (表单 META + 只写一个 compute(ctx), 模板起步)
- ctx 只含当日及以前信息 (候选评分/近60日收益/已平仓快照/组合状态/参数), 输出 weights + budget_scale; 引擎侧单仓上限/现金/敞口钳制不变
- 保存/备份导入过 AST 安全校验 → 结构解析 → 合成冒烟 三关; 回测「买入权重→自定义策略」选用, 引用失效 400, 运行期异常当日回退等权并计入统计
- 配置备份白名单新增 position_policies 分类; 回测候选 config 字段同步
2026-10-27 18:44:47 +08:00
shy3130 4355a535cd docs: 重截 19 张界面截图 + CONTRIBUTING 正文转英文
截图 (统一 1658x1194 深色主题, 路径与 README 引用一致):
- 策略: 选中「空中加油」, 7 只命中, 17 策略共 319 只, 含评分/量比/
  概念/日K/分时缩略图
- 回测: 实跑「高换手拉升」1 年期 (2025-10-27~2026-10-27),
  +32.72% / 55 笔交易 / 最大回撤 -17.26%
- 挖掘: 16 因子真实挖掘结果, 因子排名 16 行与市场环境对比/
  滚样本外/相关矩阵三图同屏
- 复盘与 AI 复盘: 由当前 AI 配置现生成, 含情绪条/龙虎榜/报告正文
- 个股分析报告/财务分析报告: 现生成的真实 AI 内容
- 开放接口: 真实空态 + 展开的六档 scope 面板
- 其余页面 (看板/自选/市场环境/异动/监控/连板/概念/财务/个股/
  AI助手/菜单标注) 全部重截, 确保数据加载完成后再截

CONTRIBUTING.md: 正文改为英文 (1-14 章), 文末以「中文版(原文)」
分隔保留原中文全文 430 行, 逐字未改。

飞书推送两张为原图: 飞书群聊界面不在面板内, 本地无 webhook 无法复现。

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-27 12:36:23 +08:00
shy3130 b08a267a87 chore(release): v0.3.18 版本号对齐 release 流水线 v0.3.18 2026-10-26 22:22:36 +08:00
shy3130 0da73df28d docs(readme): 头部徽章换技术栈版本 — 移除个人开源与 Open API/MCP 宣传位
- 徽章区: 删「个人开源」; Open API 65端点 / MCP 12工具 → Python 3.11+ /
  Node.js 20+ / React 18 (版本与 pyproject / Dev 模式要求一致)
- 统计表: 65 端点 / 6 Token 档 / 12 MCP 工具 → 3.11+ Python 后端 /
  20+ Node 前端 / 18 React·TypeScript
- 关键词行: Open API · MCP → Polars · React
- 正文开放能力章节与路线图历史记录保持不变
2026-10-26 22:17:17 +08:00
shy3130 5909155fb1 feat(ext): 盘中多盘表增量续传 — pull.since_param 游标免全量重拉
拉取前读本地目标日分区 time_field 列最大值, 以 ?{since_param}={值} 附到
请求, 源只返回新于本地的盘次; 缺口感知天然成立 (本地缺多少源补多少)。
未配置/首拉/分区缺失/schema 漂移/文件损坏一律不带参数回退整日全量,
回退方向永远安全; 历史回补与 fanout 两级拉取不注入游标。

- PullConfig 归一: 未配置 time_field 时 since_param 失效
- 分页拉取每页携带 since 过滤器
- API since_param 参数名合法性校验
- 前端拉取面板/统计卡片与 features.md 同步
2026-10-26 22:10:39 +08:00
shy3130 c932098ae7 docs(ext-architecture): P4 交付记录补齐前端消费面 (选择器/定义目录页签/导入冒烟展示)
Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-26 15:56:02 +08:00
shy3130 5d06af60b2 feat(definitions): 统一定义选择器前端 + 冒烟 API 按 id 复检 + 备份导入冒烟展示
- POST /api/definitions/smoke 支持 id 直查已存定义 (smoke_stored),
  统一选择器逐条冒烟无需回传原始定义; 不存在 fail-closed 404
- DefinitionPicker 可复用组件: 跨 kind 目录 (21 内置信号实测) +
  kind 筛选/搜索/依赖 chips/预热/坏定义隔离展示 + 逐条冒烟
- 设置页新增「定义目录」页签; Backup 导入结果新增「导入冒烟」小节
  (apply 响应 smoke 逐条渲染, 失败条目带 issue 编码)
- 验收: pnpm build 过; 浏览器 E2E 导出→覆盖导入 275 项→
  冒烟 21/21 通过零 issue; 后端 36 契约测试过

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-26 15:54:03 +08:00
shy3130 ecec9f5e54 test(factors): 修 materialize_cache 测试的注册表残留污染
uf_* 因子注册进进程级 _REGISTRY 后未注销, 累积运行时泄入
test_factor_registry 快照与 test_factor_store 断言 (6 条必挂,
HEAD 全量复现)。夹具收尾注销本文件注册的 id。

全量: 3372 过 / 0 factor 污染; 余 4 条 assistant_actions 挂
经纯净 worktree 验证为 ext_pull 会话未提交 WIP 引入, 非本分支存量

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-26 15:35:55 +08:00
shy3130 a3fcf99c7f fix(strategy): 特征依赖常量流推断 — 跨文件/属性调用点/关键字实参
- 列名经辅助函数形参传递 (_ema(col, alpha) 形态) 时, 家族全部调用点
  (含 _dep.helper 跨模块属性调用) 实参为常量即并入收集, 不再整体回退
- 修复三处缺陷: 闭包 uninferable 缺 nonlocal、关键字实参被默认值遮蔽、
  分类返回值被调用点丢弃 (fail-closed 破坏)
- 动态形参注册表与调用点解析改为跨文件合并 — 常量流跨 _*.py 生效
- full_fallback 兜底补载 instruments 股本列 (float_shares/total_shares)
- 回归: custom_v1_kanban_strict 精确推出 7 列含 float_shares,
  实盘回测 error=None (20 标的, 2.1s)

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-26 15:26:27 +08:00
shy3130 f3c30b728b feat(definitions): P4 统一定义目录 + 导入即冒烟 — 导入到可回测全链 <2s, P0-P4 收官
「一切皆扩展」的消费面与验收闭环:

- GET /api/definitions: 跨 kind (signal/factor) 统一目录视图 (label/lang/
  依赖/warmup/状态) — 统一选择器的数据半边; 单个坏定义不阻断目录 (隔离)。
- POST /api/definitions/smoke: 导入冒烟 (静态层) — validate → 编译 → 依赖
  可解析性 (enriched/指标/注册表因子/扩展字段的并集判据, 拼错列名 W001
  当场报出)。信号编译告警经日志捕获转为 issue, 不静默。
- 备份导入内置冒烟: apply_archive 对每个导入的信号/因子落盘后立刻冒烟,
  结果随响应返回 (smoke 字段); 冒烟自身异常不阻断导入 (fail-open)。
- 验收 (docs/ext-architecture-plan.md P4 ≤2 分钟): 自动化全链测试 —
  构建含新信号+新因子的备份 ZIP → apply (冒烟 ok) → 立即用引用该信号的
  策略跑回测成功, 全程 <2s。
- 前端选择器组件/参数表单自动渲染属前端后续工作, 数据与 API 契约已就绪。
- 回归: config_backup/definitions/factor 67 测试全过; ruff 新增文件全清
  (main.py/config_backup 存量告警与 HEAD 逐条一致)。

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-26 14:59:52 +08:00
shy3130 0f12836401 feat(factors): P3 T2 表达式级 Python — SKDJ 类口径零 DSL 可表达
自定义因子新增第二档编写语言 (lang=python): 受限 Python 表达式块,
只返回单个 Polars 表达式。三档编译层就此齐备: T1 DSL < T2 表达式级
Python < T3 自由 Python 策略。

- app/factors/py_expr.py: AST 白名单文法 (仅赋值/表达式语句; 名字限
  ctx/pl 与已赋值局部量; 禁 import/def/lambda/循环/推导式/下划线属性/
  map_*/apply/IO 类调用) + {ctx, pl} + 空 builtins 求值; ctx.col 构造期
  登记依赖 (无需推导); warmup 从窗口常量保守求和 (显式声明只能增大,
  少算失真是错误方向)。
- 贯通链路: FactorSpec.lang (默认 dsl, 存量零影响) → to_spec 编译分支 →
  materialize 按 lang 分发 (T2 结果同样进 P2b 内容寻址缓存, 依赖即缓存键
  输入) → API /validate 与 /trial 支持 lang=python。
- 验收 (docs/ext-architecture-plan.md P3): 看板口径 SKDJ — 9日RSV
  (分母 0 时取 50) → EMA(α=0.5) 两级 — 的 T2 单表达式与策略文件的分阶段
  列实现逐元素一致; 19 个契约测试 (含依赖登记/warmup 下限/11 种文法拒绝
  形态/物化与缓存贯通), 相关回归 568 全过, ruff 新增文件全清。

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-26 14:46:42 +08:00
shy3130 6d51bb52de feat(factors): P2b 内容寻址因子列缓存 — +10 因子热路径增量 0.1ms, P2 两项验收达成
自定义 (DSL) 因子此前每次求值都全量重算 frame_transform (132 万行帧上
每因子 ~36ms, 随因子数线性增长 — 回测/守护复验/实验室批量的共同热路径)。

- app/factors/materialize_cache.py: 键 = sha256(定义 + 依赖列内容指纹 +
  行数) — 内容指纹即失效传播 (公式变/输入任何值变 → 键变), 无需数据版本
  号。两层: 进程内 LRU (字节上限) + 磁盘 parquet (跨进程, 文件数上限,
  目录可整删)。fail-open: 任何故障回退现算。列指纹按帧记忆化 (weakref
  finalize 回收), 同帧 K 个因子每列只哈希一次 (~8ms/百万行)。
- materialize_scoring_columns 两段式: 命中列一次批量附着 (成本与因子数
  无关); 未命中逐个现算 (依赖顺序)。DSL 分阶段临时列不再泄漏进下游帧
  (与命中路径列集合完全一致)。
- 顺带修复存量 bug: winsorize(x) 省略 k 时 DSL 编译器直接 IndexError
  (该写法此前完全不可用), 补回归测试。
- 基准 (132 万行, K3→K13): 热路径 0.0ms→0.1ms (+10 因子绝对增量 0.1ms,
  基线 +400ms 线性); 冷启动 480.7ms vs 无缓存 478ms (开销 ~0.5%)。
  端到端优化器复测 trials 4.23×/含 prepare 3.16×, stats 完全一致。
- 回归: 552 个相关测试全过 (含 6 个缓存契约测试: 命中等价/输入与定义
  变更失效/损坏回退/小帧旁路/临时列不泄漏); ruff 新增文件全清。

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-26 14:36:58 +08:00
shy3130 583462a704 feat(backtest): P2a-2 共享矩阵编码 — 参数无关半边一次编码, 调参循环 3.14×
build_market_matrix 内部的参数无关成本 (build_market_data_matrix 行情
矩阵 + _encode_axes 轴 + _signal_code_matrix 信号码, 占剩余每组成本
~55%) 拆出复用:

- matrix.py 新增 PanelMatrixEncoding / encode_panel_matrix /
  build_market_matrix_from_encoding; build_market_matrix 改为两者的组合
  (单一实现, 无平行路径)。score 场随参数变化 (universe 置空), 不进共享
  编码 — 逐组散布进信号矩阵, 非有限值→nan 语义与 _float_matrix 一致。
- PreparedPanelBacktest.sim_encoding: prepare 期构建 sim 窗口编码 (失败
  回退逐组建矩阵, 只损失性能); run 侧列序 (忽略 score 列) 与行数比对
  通过才走共享编码, 否则整建 — 回退是优化放弃, 不是正确性闸门。
- 基准 (同进程交错 A/B, 15 组): 试算 4.24×, 含 prepare 3.14× (P2a 单
  面板共享为 1.8×); stats 剔除计时字段后完全一致。对应 P2 验收 ≥2×。
- 回归: tests/backtest 410 全过 (含新增矩阵级逐元素等价测试); ruff
  零新增 (与 HEAD 逐条相同)。

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-26 14:27:37 +08:00
shy3130 660ce71fca feat(backtest): P2a 面板路径 prepare-once — 参数网格共享特征面板, 调参循环 1.6-1.9×
默认后端 (polars_expr/python_history_legacy) 的优化器此前每组参数都完整
重跑 载盘/指标计算/信号注入/扩展表 join (profile: 占每组成本 ~35-60%);
只有 matrix_native 有 prepare-once。本提交补齐面板路径:

- PreparedPanelBacktest: 逐组解析依赖计划取并集 (参数驱动的列差异由并集
  覆盖), 一次加载全组复用; run 逐组做 签名校验 + 所需列子集校验, 缺列
  显式报错不静默回退 (fail-closed, 掩盖计划漂移比失败更危险)。
- _merge_resolved_feature_plans 放宽为单一后端即可 (composite 的全
  matrix_native 语义不变); _panel_backend 谓词与 run 面板分支同口径。
- 优化器: polars_expr 分支 prepare 一次 + 全部试算与最优复跑复用同一面板;
  进度新增 optimizer_prepare 事件 (shared_panel_bytes)。
- 基准 scripts/bench_optimizer_prepare.py 同进程交错 A/B (消除页缓存
  顺序偏置): 15 组实测 trials 1.72×, 含 prepare 1.62× (6 组 1.92×/1.64×);
  stats 剔除计时字段后与逐组独立加载完全一致, 交易逐笔一致。
- 回归: tests/backtest 408 全过; ruff 零新增 (optimizer/strategy 告警
  与 HEAD 逐条相同)。

下一步 (P2a-2): build_market_matrix 的面板编码 (build_market_data_matrix
+_encode_axes, 参数无关, 占剩余每组成本 ~55%) 提到 prepare 复用, 预期
含 prepare 越过 2×; 其后 P2b L2 内容寻址物化。

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-26 14:21:50 +08:00
shy3130 e382232243 feat(definitions): 统一定义契约 P1b — Store 基类收口四处持久化 + kind 注册分发
- app/definitions.py 新增 JsonDefinitionStore: 原子写 + 损坏跳过告警 +
  目录 mtime 签名, glob/日志名/逐条归一化参数化; 自定义信号/自定义因子/
  监控规则/批次四处同型实现收口为委托, 公开签名零变化。
- DefinitionKind 注册表 + validate_definition / definition_dependencies
  统一分发入口; 内置 kind (signal/factor) 惰性导入, 消费方无需预导入领域
  模块。signal 依赖提取复用编译表达式 root_names (与回测/管线同源),
  factor 复用 to_spec DSL 编译 — 不引入第二套提取逻辑。
- 验收: 新增第三种 kind = 注册一个描述器即走同一存取/校验/依赖管线
  (test_new_kind_reuses_same_pipeline), 对应路线图 P1b 验收标准。
- 契约视图归一化渲染留给 P4 消费方; 失效广播/文件锁随 P2 叠加。

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-26 14:02:54 +08:00
shy3130 a5e9d8fd28 feat(strategy): 依赖推导扩为模块家族 — 补辅助函数/_*.py 硬编码列漏推导
P1a 首版只解析 filter_history 函数体, 列引用在模块级辅助函数或 import _dep
依赖文件里硬编码时会漏推导 → 回测帧缺列 ColumnNotFoundError (响亮报错而非
静默错算, 但相对永远全量兜底仍是行为回归)。

推导范围改为整个策略文件 + 同目录 _*.py 依赖文件 (引擎加载本就把策略目录
插入 sys.path, import _dep 是受支持形态): 家族内任一文件出现动态列名/
pl.all/cs.* 即整体返回 None 保持全量兜底 — 范围放宽只会多载列, 不会漏。
新增 infer_features_from_sources 承载家族推导, 单函数版保留为薄包装。
实测基准宽度不变 (short_term_top10 动态循环仍正确走全量兜底)。

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-26 13:51:44 +08:00
shy3130 9d554a519f fix(ext): 内置预设只播种一次 — 删除后重启不再复活
用户删除 ext_gn_ths/ext_hy_ths 后, 每次重启 ensure_builtin_presets 都会重建
配置 (uvicorn --reload 也触发), 与用户自有源并存叠加每日 710 次成分股拉取。

引入 ext_data/.builtin_presets_seeded 播种标记: 预设创建仅发生在标记缺失时
(全新数据目录 / 老库首次升级); 已播种后缺失 = 用户删除过, 不复活。标记独立
于表目录, 删单表不误清。配方迁移 (_RETIRED_FACTORY_PULLS) 不受标记限制,
存活表的出厂配方升级继续送达; 中途失败下次启动幂等重试。

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-26 13:51:29 +08:00
shy3130 8cedb67c36 feat(strategy): filter_history 列依赖 AST 推导 — 消灭回测全量兜底 (P1a)
- feature_deps: 追踪 pl.col/cols 常量引用推导输入列; 动态列名/pl.all/cs.*
  等不可证明形态一律返回 None, 保持全量兜底 (fail-closed, 宁慢不错列)
- engine: REQUIRED_FEATURES 缺失且存在动态过滤时加载期自动推导
- bench_feature_resolution: legacy(空依赖) vs 推导 的解析宽度对比基准
- 实测: 看板策略等 4 个无声明策略 37→3~5 指标列 (宽度比 7~12x);
  short_term_top10 动态列名循环正确保持兜底

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-26 13:39:39 +08:00
shy3130 e9b938a3ac docs(arch): 一切皆扩展架构优化路线 (P0-P4) — 分层物化/统一契约/依赖推导
Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-26 13:39:39 +08:00
shy3130 2892c644f1 feat(backup): 配置备份与迁移 — 18 类别 ZIP 导出导入, 彻底解决多设备配置丢失
- 后端 config_backup service + /api/config-backup 三端点: 按类别导出/预览/导入
- 覆盖策略/监控/信号/因子/偏好/自选/持仓/模拟盘/挖掘候选/数据源/菜单/扩展页面/扩展数据集/语音包/历史记录
- 密钥与访问凭证默认脱敏不导出, 显式勾选才打包; 偏好/密钥 merge 写入
- ZIP 白名单路径 + 防炸弹 + 策略 AST 安全校验, 冲突默认跳过可选覆盖
- 监控徽标/导航形态/回测列表高度/设置页收起接入 uiPrefs 跨端同步
- 设置页新增「配置备份」标签页, 导出/导入向导式 UI; 16 个专项测试

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-26 12:13:19 +08:00
shy3130 b1a4dc6e38 chore: v0.3.17
Signed-off-by: shy3130 <shy3130@qq.com>
v0.3.17
2026-10-26 09:59:09 +08:00
shy3130 7fadaa907d fix(tdxquant): 分钟K整批0行 — Time数值形态归一 + Value包装解包 + 零行诊断
issue #509: 分钟同步进度正常、积分已扣, 但 0 行落库且全程无告警。三类叠加缺陷:

- Time 列归一: 原生返回混出 int/float 裸值(93100)与缺前导零 5 位串,
  旧 _minute_dt 的 6 位数字串强校验把这类返回整批静默丢弃(全天 240 根
  整型时间 → 0 行)。归一规则对齐 SDK get_market_data 的 "%06d" 拼法,
  4 位及以下按 HHMM 补零(分钟K 9:30-15:00 时段内唯一有效读法)。
- Value 包装解包: 部分环境原生返回把数据整体包在 "Value" 键里, SDK
  有同款防御而插件没有 → 0 行。client.his_dats 统一解包, provider
  解析层(_kline_rows/_minute_rows)双保险。
- 分钟请求 end 传完整时刻: 截到 00:00:00 会把当日分钟全部排除在窗口外。
- 零行诊断: 返回非空但解析 0 行(复验剔除窗口过滤的正常情形)时打出
  带字段样本的 WARNING, 进程内限 3 个标的防刷屏 — 格式漂移不再静默。

测试: +8 项形态矩阵(全天整型时间复现/Value包装/HHMM/end保时刻/
诊断含样本/限流), 组内 48 绿; 后端全量 3271 绿(ruff 零新增)。

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-26 09:58:55 +08:00
shy3130 b573ca43eb feat(mining): 挖掘锁撞锁降级启动 + 持有者诊断 + 一键强制释放
复现的原始问题: 旧实例挂死在 shutdown (热重载撞上挖掘运行) 或 worker
成为孤儿后, `.mining_process.lock` 被无限期占用, 后续所有后端实例
在 lifespan 抢锁时直接启动失败, 用户只能对着笼统报错手动找进程。

- 锁文件记录持有者 {pid, started_at, role, host} (flock 仍是唯一
  事实, 内容只是诊断线索; 旧格式 "0" 兼容, 视为持有者未知);
  新增非阻塞探测, 无需抢锁即可判断是否被持有。
- 撞锁降级启动: lifespan 抢锁失败不再上抛, 面板照常可用; 挖掘
  启动入口 (手动/自动/周度调度) 返回 409 并指引到挖掘页; 桌面版
  预检从「秒退失败页」改为留日志继续启动; 守护复验不受影响。
- 挖掘页锁占用横幅: 显示持有者 pid/角色/挖掘存储静默时长; 满足
  陈旧判定时可一键「强制停止并接管」(SIGTERM→SIGKILL→当前后端
  获取锁, 挖掘入口立即恢复)。
- 陈旧判定全部 fail-closed: 持有者信息可读、进程存活且 pid 未被
  复用 (POSIX 比对进程实际启动时间)、无进行中的挖掘运行、挖掘
  存储 10 分钟内无写入 — 任一不满足即拒绝并给出原因。不做启动
  时自动清理, 终止进程必须人工确认。

测试: 新增 test_mining_lock_admin (含真实外部持锁进程的强停回路与
五类拒绝路径), 重写 lifespan 降级契约与桌面预检继续启动契约;
后端全量 3239 通过, 前端 308 通过, ruff 零新增; 沙盒 E2E 完整
复刻「持锁→降级→强停→接管→恢复」事故场景通过。

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-26 00:01:20 +08:00
shy3130 e01fe96241 chore: v0.3.16
本次发布包含自动策略实验室 (feat(lab): 守护复验 + 稳健选冠/权重
精调 + 组合建议 + 闭环编排), 让挖掘发布的策略在真实新数据上被
持续验证 (健康/观察/退役), 冠军按稳健分选出并做权重精调, 健康
冠军间低相关可一键生成组合策略, 实验室战报聚合守护/挖掘/名额。

版本号同源: VERSION / frontend/package.json / backend/pyproject.toml /
backend/app/__init__.py 的 _FALLBACK_VERSION / release.yml 的 inputs
默认值; uv.lock 仅改项目自身条目。

Signed-off-by: shy3130 <shy3130@qq.com>
v0.3.16
2026-10-25 23:43:45 +08:00
shy3130 21279ecfa2 feat(lab): 自动策略实验室 — 守护复验 + 稳健选冠/权重精调 + 组合建议 + 闭环编排
在既有挖掘链路之上补齐「发布后持续验证与持续组合」闭环
(设计: docs/auto-strategy-lab-plan.md):

- P1 策略守护: 挖掘发布自动落 mining_gate 基线 (天然 OOS); 每日收盘
  数据更新后在新数据上切 K 段真实回测复验, 按稳健分对比基线判定
  健康/观察/退役三态 (段回测失败只降级观察不退役; 新数据 <30 交易日
  跳过本轮; retired 不再自动复验)。任意策略可手动入护 (尾随参考基线,
  判定只针对入护后新数据)。回测页稳健性验证新增「策略守护」子页。
- P2a 稳健选冠: 冠军排序分从外层折 Sharpe 均值改为 0.6×中位+0.4×最差
  (复用 robust_score); artifact 新增可选列 oos_worst_sharpe (v2 旧档
  兼容读取); strict 档发布额外要求最差折 Sharpe>0; 算法版本升
  mining-v3 并进数据指纹, 防止升级后 claim 幂等复用旧口径结果。
- P2b 权重精调: 冠军组合在 {0.5,1.0,1.5,2.0} 比率网格 (首因子固定
  1.0, 截面分位打分天然尺度不变) 两段式精调 — 外层测试窗选优 + 全窗
  复验退化>20% 放弃; 消耗 run 剩余预算 (不足自动跳过); 产物为独立
  签名候选行, run summary 带 refinement 摘要。
- P2d 组合建议: 守护运行时扫描健康冠军间近 126 个交易日日收益 Pearson
  相关性 (≥30 共同交易日, ≤0.7 入选); 前端人工确认后生成等权
  composite 策略 (fail-closed 建议对校验 + blake2b 幂等) 并自动以
  尾随参考基线入护。
- P3 闭环编排: lab_mined_slot_limit 偏好 (默认 10, 0=不限) 在发布
  门槛通过后校验, 名额满则新冠军停在 pending 等位;
  /api/backtest/lab/report 聚合守护/挖掘/名额战报 (前端总览卡);
  lab_schedule 单入口编排周度挖掘 + 日度守护 (失败互不阻断)。

测试: 新增 guardian 判定/运行时/存储/调度/API/组合与挖掘 v3 选冠/
精调用例; 后端全量 3224 通过, 前端 308 通过; 真实数据沙盒 E2E
(挖掘 v3 全链路 / 发布门槛 / 名额边界 / 复验语义 / 组合扫描 /
战报核对 / 性能延迟) 通过。P2c (overlay 候选) 按设计稿按需启动,
默认不做。

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-25 23:43:34 +08:00
shy3130 797f0c5f70 chore(frontend): 清理 klineBatchLimits 测试未用导入
Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-25 20:14:17 +08:00
shy3130 5e2c1f76eb feat(frontend): 回测页策略选择区支持拖拽调高
策略列表底部新增拖拽手柄 (指针捕获, 80-480px, 键盘上下方向键微调),
高度记忆到 localStorage, 刷新自动恢复。

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-25 20:14:17 +08:00
shy3130 df9d178060 feat(assistant): 中断提示可点击重试 + 历史会话显示时间
- 生成中断后的"已中断, 可点击重试"提示此前是纯文本, 现在是可点击按钮,
  点击即携带原上下文重发
- 历史会话列表每项增加时间行 (今天/昨天 HH:MM, 更早 MM-DD / YYYY-MM-DD)

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-25 20:14:17 +08:00
shy3130 fff52f93cc feat(settings): 自定义提示音语音包上传
设置页可上传/试听/删除自定义提示音 (mp3/wav/ogg 等 8 类, ≤4MB),
存储 data/sound_packs/, 键名 custom:<文件名> 复用现有 alert_sound
偏好通道, 零新配置项; 删除当前正在用的语音包时自动回退默认提示音。
后端 6 项测试 + 前端 3 项测试。

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-25 20:14:17 +08:00
shy3130 62c8a8bd56 fix(backtest): 矩阵回测接入扩展时序数据
扩展数值列按设计不落 enriched parquet (只存 14 列), 此前矩阵回测引用
ext_* 字段直接报 fields unavailable — 叠加条件/评分引用扩展数据的策略
无法回测, 扩展数据失去回测意义。

修复: 引擎在矩阵加载后按矩阵自身 (日期×标的) 骨架现场注入时序模式数值
扩展字段 (attach_matrix_ext_fields, 与策略页帧路径同一台 PIT 安全 join,
缺失补空值=条件不命中), 与财务因子 attach 同构; parquet 矩阵缓存不受
影响。快照模式与字符串扩展字段仍拒绝 (快照回看历史=未来函数), 引用时
前置校验给出明确报错。

实测: 隔夜溢价精选·迭代优化 + 人气排名 20~100 叠加条件, 回测 1.1s 跑通,
交易数 29→22 证明过滤真实生效; 新增 7 个单测 (对齐/NaN/拦截/叠加联动/
端到端正反例), 全量回归 3131 通过。

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-25 20:14:17 +08:00
shy3130 da9dbca422 feat(backtest): 稳健参数筛选与滚动样本外检验重构 (P1-P4)
参数排名从单窗样本内得分改为 K 段折外稳健分 R = 0.6×中位 + 0.4×最差
(设计: docs/robust-optimizer-plan.md), 四阶段全部落地:

- guards 共享护栏: 主目标白名单 + 最小交易数门槛 (fail-closed, 缺交易数
  按不达标处理), 两模式一处实现
- robust_optimizer: 等分切窗 (2-6 段, 每段≥14天) / 稳健分 / 冠军收敛诊断
  (unanimous/majority/scattered) / Top-20 全窗 IS 细化与退化率 /
  高原判据 (邻域得分衰减, 零额外回测); worker 接线 robust_optimize 任务
- 滚动样本外检验补强: 每折 OOS 最小交易数门槛 (无效折透明跳过),
  前端折预览 / 参数漂移轨迹 / 采用最新折参数
- 前端: 冠军卡 (收敛/高原徽章/乐观偏差) + K 段排名表 + 验证窗预览 +
  应用参数闭环 (POST /strategies/config, 可逆); SSE 重连与跨设备接回
- P4 摒弃旧路径: 删 /optimize/stream 与 /optimize/cancel 端点及 worker
  optimize 任务类型; 白名单全面生效 (optimizer.VALID_OBJECTIVES 收敛到
  guards; walkforward 端点校验退化目标 400)
- 附带修复: 叠加条件×矩阵路径 SignalMatrix 只读违规 (np.where 产物
  可写), optimizer_trial 轻量统计恒保留 n_trades

实测: 126 组合全市场网格 1.71× 旧版耗时 (视图复用优化自 2.01×; 差额
为引擎层每 run 固定开销, 详见方案文档第九节); 全量回归 3131 通过。

api.ts 同时带入稳健优化折预览客户端与声效语音包 API 客户端
(语音包功能随后续提交落地界面)。

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-25 20:14:10 +08:00
shy3130 c0daaa8302 docs(readme): 同步测试数与助手动作工具数
- 测试数 2400+ → 3000+ (后端 3096 + 前端 55 个测试文件)
- 动作工具 4 → 5: 补创建 AI 策略草稿; 补免确认开关说明 (默认关,
  轮次检查点安全阀不受影响)

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-25 17:40:19 +08:00
shy3130 7f6cad0f8f feat(factors): 因子生命周期状态下发 + 发现页三视图重构 (批量/单因子/挖掘)
- 因子注册表按 id 合并下发完整生命周期 status (draft/active/watch/retired),
  registry 的 stability 降为其二元投影; asset_type 过滤适用资产
- FactorDiscovery 重构为 批量/单因子/挖掘 三视图 (MiningWorkbench),
  标的列表解析兼容中英文逗号/分号/顿号/空白分隔
- FactorLibrary/FactorEditor/回测页配套调整

Signed-off-by: shy3130 <shy3130@qq.com>
2026-10-25 17:31:16 +08:00