shy3130
|
2d629197c1
|
fix(backtest,services,frontend): 回测成交口径/任务注册表并发/查询键一批正确性修复
回测成交口径:
- close_t 按收盘价成交的建仓日: 当日 high 发生在建仓之前, 不得进入移动止损
峰值 (峰值虚高会把风控线上移、退出提前) — 矩阵独立/矩阵组合/legacy 三条
路径同口径; 新增回归测试锁定 open_t+1 对照组不被误伤
- 矩阵路径补收盘封死跌停拦截 (含一字), 经 pending_exit 递延到下一可卖日,
与独立/legacy 路径同口径 (此前尾盘封板股按跌停价"卖出"低估亏损)
- #388 当日指标纪律同口径: 盘中成交不可知当日收盘, 代数剔除当日 enriched
- 分钟回放: 入场价用前复权口径 (与日线出场同尺度); 除权日涨停参考价按
ex_factor 还原 (直接用 raw_prev 会把涨停价算高, 除权日封板拒买漏检)
- 指标管线: 涨停参考价除权口径修正 + 夏普用样本标准差 (ddof=1, 与 engine 一致)
- 回测任务: _acquire_or_evict_job 收口同 key 复用/强制重建 (参数不同先取消
旧任务, 避免旧任务占着重任务槽跑完)
服务与并发:
- task_registry 读-改-写加锁: 两个前端 fire-and-forget 并发上报时后写者
覆盖先写者 (丢终态翻转或整条记录); 文件写入本身原子, 锁只护 RMW 段
- quote_service 生命周期锁串行化 start/stop/enable 的 check-then-act (双标签页
并发开关会起两条轮询线程 → 双倍拉取配额 + 重复 SSE 广播)
- 系统通知投递移入专用单线程池: notify_adapter 底层 subprocess 逐条最长 5s,
在 _poll_loop 同步执行会让告警风暴阻塞一轮监控评估, 拖慢行情拉取与推送
- sector_monitor / minute_refresh / wecom_bot: 同类单实例与停止时序加固
- ai_provider: 401 识别加词边界 (避免模型正文含 401 数字串误判鉴权失败并
附出不相关指引); 自定义可执行路径校验可执行位
- api/data: 清空数据期间暂停全量分钟增量线程 (否则"清完又被写回部分今日
数据"); 状态接口偏好/能力探测异常降级而不是 500
- api/kline: 失效内存 enriched 快照 (非空缓存不校验 generation, 只刷 DuckDB
视图会让重建结果对自选/筛选/监控不可见直到进程重启)
- api/position_policies: 非法 ID 纵深防御按不存在处理
前端:
- assistant store: 生成终态 (中断提示/流式收敛) 钉在发起会话, 切换或删除会话
不再把"已中断"写进无关新会话
- backtestTask: 键上挂着旧任务且新参数不同 (不同 job_key) 时先取消旧任务,
避免其占着重任务槽跑到自然结束; 同参重跑跳过取消 (后端按同 key 复用 /
force 重建已完成任务)
- 查询键集中与正确性: QK.instrumentNames (排序去重, 同一集合不同来源顺序
复用缓存)、QK.kline 滚动窗口空串边界 (useQuoteStream 焦点股增量合并可
修补)、regimeHistory 用实际请求三元组 + 裸前缀失效全部变体
- Data 页 / Regime / SectorRotationCard / RuleEditor / monitor / lots /
stock-analysis 接入集中键, useQuoteStream 对齐
验证: 后端全量 3546 passed (含 close_t 峰值/分钟回测/跌停递延/并发上报等
新增用例); 前端 49 文件 348 用例 + pnpm build 通过; ruff 改动文件零新增
(141 vs 基线 142)。
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-30 00:20:52 +08:00 |
|
shy3130
|
e2c84dbeca
|
fix(dragon-tiger): thscode 为 null 的退市/B股标的归一化, 修复龙虎榜崩溃
用户反馈: 展开复盘页龙虎榜 (2026-10-29 榜单 72 条) 前端崩溃。
根因: fuyao 对退市整理期股/B股返回 thscode=null (ticker 有值) — 今天
首次上榜的萃华退(002731)/宁通信B(200468)/动力B股(900920) 3 条 null
thscode 被后端原样透传, 违反前端 DragonTigerStockItem.thscode: string
契约 (下游按 string 使用, 收到 null 即崩)。
- dragon_tiger 服务新增归一化 (新拉取 + 历史缓存读回共用):
thscode 缺失时由 ticker 推导市场后缀 (6xx/900→SH, 0xx/3xx/200→SZ,
4xx/8xx→BJ), 两者都不可用则丢弃并告警; 游资席位嵌套 rows 同样处理
- 前端: 类型放宽为 string | null (如实反映数据源现实), 榜单卡片统一走
_dtCode/_dtLabel 兜底 (旧缓存/异常数据源也不再崩), 无代码行不触发
onOpenStock
- 实测真实数据: 72 条归一后 0 条 null; 三条退市/B股 →
002731.SZ / 200468.SZ / 900920.SH; 席位嵌套 rows 同样干净
验证: 后端新增 6 条归一化用例 (ticker 推导/不可识别丢弃/嵌套 rows/
缓存读回/端到端); 前端新增龙虎榜卡片回归 2 条 (展开 72 条不崩 + 点击
null 行以 ticker 兜底回调); 后端全量 3546 passed; 前端 49 文件 348
用例 + build 通过; ruff 零新增。
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-29 22:35:30 +08:00 |
|
shy3130
|
b8f1ebaaf0
|
fix(mining): 旧格式锁也能定位持有者并强制释放, 不再永久卡挖掘
用户反馈: 挖掘工作台一直提示「挖掘锁被其他进程占用 — 锁文件为旧格式,
无法定位持有进程」(v0.3.17+ fail-closed 设计)。根因: 锁内容是 v0.2 时代
写入的 b"0" (无 pid), 持有者为升级前启动、仍在运行的旧版后端残留进程;
flock 是 OS 级锁, 进程存活即一直占用, 旧版本无法被识别 → 强制释放按钮
永不出现, 用户只能去任务管理器逐个猜进程。
- mining_process_lock: 新增 locate_lock_holder_pid — 锁内容不可读时用
lsof (POSIX) / psutil (跨平台兜底) 反查打开锁文件的进程; 只认本产品
形态 (python/uvicorn/desktop/tickflow), 且连续两次扫描命中才采信,
避免误杀瞬时探测或无关进程 (误杀是破坏性操作, 宁可定位失败)
- mining_lock_admin.lock_status: 旧格式锁 → OS 反查持有者, 继续走既有
fail-closed 判定 (无进行中挖掘 + 存储静默 >=600s 才允许释放);
状态新增 holder_source 字段
- 前端横幅: 展示「已通过系统扫描定位」并出现既有「强制停止并接管」按钮;
定位失败时保留手动指引
- 设计纪律不变: 仍只提供人工确认的强制释放, 不做启动自动 kill
验证: 新增 4 条用例 (旧格式持锁进程定位 / 强制释放完整接管 / 挖掘活跃时
仍拒绝 fail-closed / 锁空闲不误报); 撤销集成时 3 条红, 恢复后绿;
后端全量 3540 passed; 前端 build + tsc 通过。
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-29 21:21:13 +08:00 |
|
shy3130
|
02712af01b
|
chore(release): v0.3.23 版本号同步
- 修复 #514 漏接 failed_out 参数导致「数据修正/自检修复」路径同步必炸 (b590e5ad)
- 迁移 skip 分支补捞 preferences.json, 防升级后引导重弹 (5ff6e159)
- 数据源偏好回退 tickflow 留痕告警 (3c0ad017)
- 回测页 busy 期统计为 null 不再误判缺数据 (9659237a)
- 数据页 busy 降级 storage=null 崩溃修复 (da4ed647)
- 模拟盘台账补品种名称 (f3ff1d5e); 回测强制重跑按钮 (939149e8)
- 消除 "获取数据" 误弹 (dd589733/e975f782 已随 0.3.21)
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-29 18:52:20 +08:00 |
|
shy3130
|
3d89e8a126
|
test: 宿主状态隔离补齐 + Codex env_key 正向覆盖 + node:test 转 vitest
- test_assistant_actions: auto_approve_enabled 直读宿主 preferences.json,
本机开「动作免确认」时 4 条门控用例全红 (审批拒绝后动作仍执行 ==
测试环境失真, 非产品 bug); _run_chat 统一 patch 免确认关闭
- test_ai_provider: secrets 排除断言隔离宿主 ~/.codex/config.toml
(宿主配 env_key provider 时随机翻红); 补 env_key 正向注入与非法名
拒绝 2 条用例
- neighborPrefetch / DimensionMembersDialog 测试由 node:test 转 vitest
(文件名 *.test.ts 本就在 vitest 收集范围, 此前每次 vitest run 恒报
2 个收集失败掩盖真失败); 转换后 5 条用例全过
前端 vitest 48 文件 346 用例全绿; 后端全量 3536 passed。
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-29 18:39:40 +08:00 |
|
shy3130
|
5ff6e15995
|
fix(desktop): 迁移 skip 分支补捞 preferences.json
_migrate_legacy_data_dir 的 has_new_data skip 分支此前只捞 secrets.json
(0669204c), preferences.json 不捞 — 偏好丢失会让 onboarding_completed
回落默认 False, 升级后全屏引导重弹, 表现为「昨天同步过数据, 升级后
又被要求获取数据」(用户反馈链路)。函数泛化为 _rescue_legacy_user_data:
secrets.json + preferences.json 逐项捞回, 旧有新无才拷, 异常只告警。
验证: 新增 preferences 捞回/不覆盖 2 条用例; 原有 secrets 捞回 3 条
语义不变全绿。
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-29 18:39:40 +08:00 |
|
shy3130
|
3c0ad0179c
|
feat(data): 数据源偏好回退 tickflow 时告警留痕
7 个 provider getter (daily/adj_factor/minute/full_minute/depth5/
realtime/financial) 白名单不命中时一律静默回退 tickflow — 配置的源
失效后行为悄悄变免费档, 用户与排查者均无感知 (fuyao 事件定位难点)。
统一走 _validated_provider: 回退即 logger.warning 带偏好键/原值/可用列表。
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-29 18:39:40 +08:00 |
|
shy3130
|
b590e5ada3
|
fix(data): sync_and_persist_daily_batch 补接 failed_out 参数
#514 (285dd9b7) 在 daily_pipeline 修复/定向分支传了 failed_out, 但函数
签名漏接 → TypeError: sync_and_persist_daily_batch() got an unexpected
keyword argument 'failed_out' — v0.3.21/22 所有走「数据修正/boot 自检
修复/实时 gate 修复」路径的同步必炸 (用户截图实锤), 恰好是用户恢复数据
的路径; 普通增量分支不传该参所以未暴露。
签名补 failed_out 出参, _finalize 统一透出内部分块拉取失败清单, 对齐
#514 意图 (单票失败上浮 stage_errors 而非静默当成功)。
验证: 新增回归测试 2 条 (修复前红 — 复现截图 TypeError; 修复后绿);
bare_symbols/fuyao 流式同步 14 个相关用例无回归; 后端全量 3536 passed。
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-29 18:39:40 +08:00 |
|
shy3130
|
da4ed64707
|
fix(data): busy 降级期间 storage 为 null 不再使数据页整页崩溃
用户反馈桌面客户端数据页 "Unexpected Application Error! Cannot read
properties of null (reading 'total_size_mb')"。根因: /api/data/status 在
预热/同步/修复期间 (busy) 不重算存储统计, 冷启动缓存从未热过时
_get_storage 返回 None — 前端存储卡片 s.storage.total_size_mb 只判了 s
没判 s.storage, 6 处访问全部抛 TypeError, 整页被错误边界接管。与此前
"立即获取数据"误判同族 (busy 降级契约: 空值不代表无数据)。
- DataStatus.storage 类型改为 {...} | null 诚实反映降级契约, 编译期
强制所有消费点判空
- 数据页取安全别名 const storage = s?.storage, 总大小与表统计/扩展数据
全部 storage?. 判空, 缺值降级显示 — 或 0
- 后端补契约测试: 冷启动 busy 且缓存未热时 _get_storage 返回 None
(原测试只覆盖缓存热过后清空仍留 stale 的路径)
验证: Data.status.test 修复前红 (错误与用户截图逐字一致) 修复后绿;
后端 test_data_status_busy 10 passed; 全量 vitest 338 passed; pnpm build。
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-29 13:09:56 +08:00 |
|
shy3130
|
939149e8a0
|
feat(backtest): 强制重跑 — force 绕过同参数任务结果缓存; 修 cancel key 对齐
策略回测按全参数 md5 作 job_key, 已完成任务结果保留 5 分钟 — 同参数再次
运行直接命中缓存返回旧结果 (重连/切页恢复设计的副产物), 用户改完数据后
重跑拿到的仍是旧行为产物, 此前没有绕过手段。
- startBacktest/strategy_stream 新增 force: 掺入 job_key 使其不命中缓存
必然重算; 不动任务复用/并发语义, 重连与取消按同一 qs 重算 key 天然对齐
- 运行回测旁新增「强制重跑」按钮 (RefreshCw, 次要样式, 悬停说明语义),
disabled 条件与主按钮一致
- 补算环境并继续改为 handleRun(true): 已失败任务的 error 同样被任务缓存
保留, 补算成功后自动重跑不带 force 会命中同参数旧 job 直接重放补算前的
报错 — 用户实测补算完成后仍提示"缺少前一交易日环境 2019-10-22 等 112 天"
即此因 (实测数据已补齐: 2019-10-22~2026-10-29 共 1703 行无缺口)
- 修预存 bug: /strategy/cancel 重算 job_key 漏了 minute_fill 与
regime_filter — 开了分钟K精确回测或市场环境过滤的任务停止按钮失效
验证: test_backtest_stream_force 3 passed (force 改 key 且幂等; cancel 带
force/minute_fill/regime_filter 的 qs 能取消到、缺参取消不到 — 走真实
qs→key 解析路径不启动回测线程); ruff 与 HEAD 对照零新增; pnpm build 通过。
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-29 13:09:50 +08:00 |
|
shy3130
|
9cd8792c9e
|
chore(release): v0.3.22 版本号同步
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-29 11:10:34 +08:00 |
|
shy3130
|
0669204cfb
|
fix(desktop): macOS 升级跳过整体迁移时单独捞回 secrets.json
用户反馈 (v0.3.20): 升级后有数据却无法开启实时行情 (fuyao 源)。根因链:
fuyao 插件注册要求 API Key 可见 (secrets.json 优先), macOS ≤0.3.6 用户
升级后先跑过新版 (新 data 已有行情), 再从废纸篓恢复旧包数据时, has_new_data
守卫跳过整目录搬迁, secrets.json 未随行 — Key 读不到 → 插件不注册 →
realtime_data_provider 偏好静默回退 tickflow → 免费档无实时权限 → 开启被拒。
修复: 守卫跳过整体搬迁时, 单独捞回新目录缺失的 user_data/secrets.json
(AI/数据源密钥, 用户重配成本最高的文件)。新目录已有则绝不覆盖 (尊重
用户重配); JSON 非法/为空跳过不制造坏文件; copy2 保留 0600 权限位;
任何异常只记警告绝不影响启动。整体搬迁分支 (新目录基本为空) 原本就
逐项搬 user_data, 两条路径均已覆盖。
验证: test_macos_data_dir 12 passed (存量 9 + 新增 捞回/已有不覆盖/
非法跳过 3 条); 守卫语义不变 (旧目录整体保留、新目录已有行情不被覆盖)。
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-29 11:10:09 +08:00 |
|
shy3130
|
2fb2fa1537
|
fix(ai): Codex 401/超时附登录指引 + macOS PATH 兜底 + 陈旧运行目录清扫
继 2c0141f3 (草稿模型探测 + env_key 鉴权) 后的 Codex CLI 体验第二批:
- 401/超时错误附登录指引 (_codex_missing_auth_hint): 新版 Codex 凭证可存
系统钥匙串 (不落 auth.json), 隔离 CODEX_HOME 复制不到, 用户面对裸
401/长时间挂起无从下手 — 现在直接提示 codex login 命令
- macOS GUI 启动只继承最小 PATH, npm/brew/ChatGPT.app 内置的 codex 均
找不到 — 与 Windows Desktop 兜底对称, 显式探测常见落位
- _sweep_stale_codex_run_dirs: 进程退出中断 finally 清理时残留的临时
运行目录按 mtime 兜底清扫 (每进程一次)
验证: test_ai_provider/test_ai_probe 合计 70 passed (401 带/不带指引、
超时附指引、macOS 三种落位、清扫只删陈旧+进程内一次、探测透传失败信息);
test_ai_probe 既有用例补 sweep 打桩 (与实现同批提交, 拆开 CI 不稳)。
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-29 11:10:06 +08:00 |
|
shy3130
|
e6fc60078f
|
chore(release): v0.3.21 版本号同步
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-29 10:39:58 +08:00 |
|
shy3130
|
2c0141f3eb
|
fix(ai): 修复 Codex 连接测试与自定义源鉴权
使用草稿模型执行连接探测,并向自定义 provider 传递其声明的鉴权环境变量。认证续期仍需单独处理。
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-29 10:38:03 +08:00 |
|
shy3130
|
1c57c54bad
|
fix(ui): 切换 fuyao 后刷新实时行情权限
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-29 10:25:40 +08:00 |
|
shy3130
|
e975f78240
|
fix(ui): 同步和修复期间不再误判无数据
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-29 10:25:29 +08:00 |
|
shy3130
|
a17742c97d
|
chore(release): v0.3.20 版本号同步 (package.json 单源派生)
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-28 13:40:30 +08:00 |
|
shy3130
|
b6c35a9b64
|
feat(ext-data): 扩展序列粒度 auto/intraday/daily — 日级近N日序列
扩展表此前只有日内多盘一种时序形态; 无时间列的每日快照表 (板块成员/评分等)
无法画趋势。新增序列粒度:
- PullConfig.granularity 三态 (auto/intraday/daily, 默认 auto): auto 按时间列
值形态判定 — 含非零 HH:MM:SS 判 intraday, 日期形态/00:00:00/无 time_field
判 daily; 显式声明优先于判定。schema/list 透出 granularity_effective。
- series 端点日级分支: 无需 time_field, 取近 N 日分区按日聚合 (末次非空),
支持标的过滤与 chartDays; 日内分支响应带 granularity 标识。
- 前端拉取配置加「序列粒度」选择 (auto 显示判定结果), 列自定义器按 effective
粒度分流: 日内保持现状, 日级提供近N日柱/线/文本与图宽高配置。
- ExtSparkChart 修全等值退化: min===max 时归一化柱形无意义 (全负值画满格、
全正值画 1px 线), 改回退文本直显。
auto 默认与旧行为完全一致 (向后兼容); 无 time_field 不再 400 而按日级处理。
验证: test_ext_granularity 16 条 + 快照/时间列契约适配; 前端 build + 321 测试。
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-28 12:46:51 +08:00 |
|
shy3130
|
977248ceb2
|
fix(api): /api/data/status 同步期忙时读旧缓存 — 不再 30s 超时
同步进行中 (active job pending/running 或指标预热未完成) 时, /status 的 12 张表
聚合 + 存储扫描仍要抢数据槽并全量扫描, 与前端 2s 轮询叠加导致「请求超时(30s)」。
busy 模式改为直接回最近一次成功聚合的过期缓存 (无缓存则该表置 null), 不重算;
空闲路径 TTL 语义不变; 僵死 active_id 由 job 终态判定兜底, 不会永久卡 busy。
验证: test_data_status_busy 7 条 (忙时旧缓存/无缓存置空/空闲 TTL 不变/触发条件/
端点接线); 全量 pytest 通过。
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-28 12:46:45 +08:00 |
|
shy3130
|
bc5d213bea
|
perf(backend): DuckDB 读并发 — cursor 独立连接+信号量限流, DDL 收口 refresh_view
单连接全局互斥下, 同步期任一长查询(全视图扫描)把所有交互读堵到前端 30s 超时,
不同端点轮流失害 (/status 事故即此形态)。cursor() 本就是同一内存库实例的独立连接
(MVCC 快照隔离; duckdb 1.5.3 实测 6 读线程+2 换视图线程共 1800 次零异常),
execute_all/execute_one 改为信号量限并发 (TICK_DUCKDB_READ_CONCURRENCY,
默认 3, 1=完全串行旧行为), 根连接运行期仅作连接工厂。
并发 CREATE OR REPLACE VIEW 同名视图会抛 Catalog write-write conflict (实测),
运行期视图重建一律收口 repo.refresh_view (_ddl_lock 串行, 与读不互斥), 同时消除
kline_sync/daily_pipeline/extend_history/api-kline 共 7 处绕锁直连 db.execute
的线程安全隐患 — 两同步路径同时刷同一视图的静默失败一并修复。
验证: 新增 test_duckdb_read_concurrency (并发重叠/串行回退/视图重建/DDL 零冲突/
坏名字拒绝/env 钳制) 6 条; 全量 pytest 3479 通过; ruff 码级零新增(消 3 条存量);
基准 376ms 长查询持锁时短读 271ms → 0.1ms。
Signed-off-by: shy3130 <shy3130@qq.com>
|
2026-10-28 12:46:41 +08:00 |
|
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
|
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
|
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 服务级重试配套
|
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
|
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
|
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
|
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
|
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
|
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>
|
2026-10-26 09:59:09 +08:00 |
|