Files
one_divine_lot/docs/04-迭代记录/22-策略计算字段与策略tab静态化/迭代复盘.md
T
kyugao ec02a791ee 迭代22+23: 策略tab静态化 + 计算字段(数字/判定型)+ 网格超市信号字段
- R-027 静态化:策略恒为内置两项(不可增删改名,保留显隐/排序);设置页移除「策略分组」;
  字段配置入口迁到策略 tab 内「列设置」旁(FieldConfigDialog + schema-update 单策略写入)
- R-026 计算字段:自写公式引擎(中文变量、四则/括号/round·abs·min·max、缺值短路→—)+
  变量目录(行情/合约/持仓/自定义字段)+ strategy-positions 逐行现算(只读内存缓存,不落库、列只读)
- R-028 判定型:比较运算 + and/or + inferResultKind + 结果类型一致性校验 + 判定列 ✓/— 渲染;
  网格超市落地 可下空单=涨停价>基准值+网格大小、可下多单=跌停价<基准值-网格大小
- 变量选择改标签平铺(老师反馈);公式手册 docs/99-其他材料/计算字段公式说明.md
- 约束同步:产品约束-002/003/004/009/013/014、技术约束-014/015/022/023/024、UI约束-002/003/005/008
- 回归:新增 test-r026/test-r027,更新 r011/r013/r017,17 个脚本全绿;typecheck/build 通过
2026-09-10 14:05:06 +08:00

8.9 KiB
Raw Blame History

迭代复盘:22-策略计算字段与策略 tab 静态化

结论

实现完成(两阶段全范围),待老师人工验收(尚未宣告验收通过)。事实:策略 tab 静态化 + 字段配置入口迁移(R-027) 与计算字段(R-026)均已落地;pnpm typecheck 0 错、pnpm build 通过、17 个回归脚本全绿(含新增 2 个)。

事实记录

阶段一 · 策略 tab 静态化与入口迁移(R-027)

  • src/settings.js:新增 BUILTIN_STRATEGIES(内置两项:网格超市 grid-supermarket / 手动做T manual-t)、 isBuiltinStrategy / assertBuiltinStrategy / normalizeFields;字段定义真相源迁到 strategyFields getStrategies 恒返回内置两项、缺失时兼容读取旧 strategies[].configSchemagetStrategyFields / updateStrategyFields 为唯一读写入口);normalizeTabs 改为常量派生3 内置 tab + 2 策略 tab 只保留存量 visible/order 偏好、丢弃未知条目、补齐缺失条目),updateTabs 只接受内置 id normalizeStrategyColumns 的字段列来源改读 getStrategyFields;新增 scopeValue 容错读取 (测试桩无 get 不炸);退役 addStrategy / removeStrategy / renameStrategy / updateStrategies / appendStrategyTab / removeStrategyTab / DEFAULT_STRATEGIES
  • src/api/strategies.js退役 strategies/add | strategies/remove | strategies/update(调用返回 not-found); 新增 strategies/schema-update { strategyId, configSchema }(唯一写路径)+ validateConfigSchema (结构 / key 唯一 / 展示名唯一 / 内置变量名冲突 / 枚举选项 / 公式校验,失败统一 code='field-validation'); 新增 formula/variables(变量目录)与 formula/trial(试算)。
  • 设置页SettingsSection.jsx):「策略分组」子 tab 整体移除(含 CRUD 与删除确认)→ 设置页仅 「Tab 设置 / QMT 连接配置」。
  • 字段配置弹层FieldConfigDialog.jsx 新建 + StrategyFieldsEditor.jsx 改造):策略 tab 顶栏 「字段配置」(列设置左侧)→ 锚定弹层(520px / 70vh / 内部滚动);字段列表 + 添加/编辑/删除 + 底部 [关闭]/[保存字段];dirty 时关闭/外点/Esc 二次确认;保存走 strategies/schema-update

阶段二 · 计算字段(R-026

  • src/formula/evaluator.js(自写零依赖引擎,不用 eval/Function):词法支持中文标识符 + 全角归一 (()+-×÷),递归下降解析(四则 / 括号 / 一元负 / round·abs·min·max;长度 ≤500、深度 ≤32); validateFormula 返回 {ok,vars}{ok:false,error:{code:empty|syntax|unknown-var|unknown-func|arity,message,position}} 求值缺值短路(任一变量 null → 整式 null)、除零/非有限 → null、最终结果浮点归一|v|<1e12 四舍五入 10 位, 消除 0.7000000000000002 类噪声;中间步骤不归一再保精度——首版曾因每步归一导致 6.66666667 精度劣化,已改)。
  • src/formula/variables.js:变量目录单一入口(行情 7 项 / 合约 2 项 / 持仓账本 3 项 + 运行时按策略 非 formula 字段展示名展开「自定义字段」组);allowedVarNames 排除 formula 字段(零循环依赖); buildContext 取数(昨收兜底合约 preClose、布尔 → 0/1、空值 → null)。
  • src/formula/FormulaService.jscomputeRowsstrategy-positions 行附 computed;行情/合约 只读 QuoteHub 内存缓存(不读穿透)无 formula 字段直接返回原数组(零开销);值不落库。
  • 前端:字段表单类型「计算」分支(等宽公式框 + 「+ 插入变量」分组菜单 + 试算 + 小数位 0-4 默认 2; 保存失败公式框描红 + 服务端文案);持仓表计算列只读(表头 ƒ + title 公式原文、按 toFixed(decimals) + 单位 格式化如 6.67 % / 700.00 元、缺数据 、点击不进内联编辑);历史持仓行 ;列设置弹层列名带 ƒ

实机数据核实(实施前)

  • ~/.dsh/settings.yaml:策略仅两个内置(网格超市 5 字段 / 手动做T 1 字段);
  • ~/.dsh/one-divine-lot/store.dbstrategy_holdings 13 / 3 行,交易与归属数据只涉及这两个策略 → 无自建策略,静态化零数据迁移

验证

  • pnpm typecheck → 0 错;pnpm build → 通过(lib 32 文件 + client bundle 195545 bytesscripts/wrap-client.mjs 正常);
  • 回归脚本 17 / 17 全绿
    • 新增 scripts/test-r027-static-strategies.mjs 35/35(策略常量 / 旧定义兼容 / 单策略写入 / tabs 归一化 / 端点退役);
    • 新增 scripts/test-r026-formula-fields.mjs 48/48(引擎 / 目录 / 上下文 / 现算 / 保存校验 / 试算);
    • 更新 test-r011-tabs 22/0、test-r011-api 17/0、test-r013-custom-fields 23/0、 test-r013-columns 18/0(期望值按 R-015 行情列 + R-027 真相源更新)、test-r017-candidates 12/0(策略 id 改用内置);
    • 其余(r009 系列 / r016 / r018 / quote-sync / position-sync / health / mcp)零改动全绿。

偏差、顺带修复与发现

  1. generateStrategyId / PINYIN_MAP 保留(方案原文列入退役):QMT 连接 id 生成 generateQmtConnectionId 仍依赖,本轮不动(已回写技术方案)。
  2. 真 bug(实施中发现并修复)normalizeStrategyColumns 仍读旧 strategies[].configSchema 字段定义迁到 strategyFields 后策略列会丢失字段列 → 改为 getStrategyFields(scope, strategyId)。 教训:真相源迁移必须全量搜「读点」而不只是「写点」。
  3. 兼容修复strategy-positions 新增 settings 依赖后,测试里无 get 的 settings 桩会抛错 test-r016/test-r017 暴露)→ 新增 scopeValue 容错读取。
  4. 顺带修复迭代 20 复盘遗留第 1 项test-r013-columns 期望过期(R-015 增加 4 个默认隐藏行情列后应为 12 列)——本次随实现更新期望并补「strategyFields 优先」用例。
  5. test-r017-candidates 策略 id 迁移attribution-targetsgetStrategies 取策略表, 静态化后仅内置两项 → 测试改用 manual-t / grid-supermarketR-027 的必然结果,非缺陷)。
  6. 交互边界修复:字段配置弹层的「外点关闭」原以弹层面板为界,点「字段配置」按钮自身会触发放弃确认 (dirty 时甚至静默卸载)→ 改为以锚点容器(含两个按钮)为界。
  7. 工作区背景(非本轮产出):仓库工作区另含迭代 19/20/21R-022/R-023/R-024/R-025)的未提交改动, 本轮未触碰其逻辑,仅在其上叠加;建议老师确认后一并提交。

遗留与风险

  • 行情 miss 显示 :计算列取数只读内存缓存、不读穿透(技术约束-023);某 code 无快照时该格为空, 等 QuoteSync 下轮(≤5s)覆盖。若老师更希望「宁可慢也要立刻有价」,可改判为读穿透。
  • 需要重载插件才能人工验收~/.dsh/profiles/web/node_modules/one-divine-lot 是指向本工作区的软链, lib 已构建完成;老师侧需重载插件(或重启 dsh web)后在页面验收(未由我启动任何服务)。
  • strategies[].configSchema 仅只读兼容:本机字段定义在其首次保存后落入 strategyFields (不写迁移脚本、不动库数据)。
  • 自建策略若未来出现:读取忽略、tab 丢弃,其 strategy_holdings 数据保留在库(本机无此情况)。

待老师确认事项(人工验收)

验收标准.mdA1A11(重构)+ B1B12(计算字段),重点四条:

  1. 设置页无「策略分组」;策略 tab 恒两个、不可增删改名,但 Tab 设置仍可显隐/拖拽排序;
  2. 策略 tab 顶栏「字段配置 / 列设置」可用,字段增删保存后表格列跟随、重启后定义仍在;
  3. 计算字段可用:中文变量公式 + 变量选择器 + 试算 → 持仓列只读显示结果(ƒ 标记 + 悬停看公式);
  4. 边界:非法公式/未知变量/名称冲突被拒 + 描红;缺数据与历史行显示 strategy_holdings.values 不含计算字段键。

经验沉淀(候选)

  • 并行委派的契约必须在开工前冻结:本轮前端由子代理并行实现,期间服务端 settings.js 仍在演进 (子代理观察到 mtime 变化、并在报告里提出「疑似工作区未冻结」)——契约冻结 + 文件集互斥是并行可行性的前提。
  • 真相源迁移要全量搜读点:本次 normalizeStrategyColumns 差点漏改,靠既有回归脚本的红灯暴露; 遗留的旧键兼容读取(而非直接删键)让迁移零风险、零脚本。
  • 测试期望也需要跟着设计演进test-r013-columns 的过期期望在迭代 20 复盘就被记录却未处理, 本轮顺手清偿,避免「红灯常态化」。