Commit Graph
280 Commits
Author SHA1 Message Date
shy3130 db300cad45 refactor(ui): 页面包更名为页面插件
消除断句歧义, 与数据源插件命名对齐; 仅改文案, 代码层标识不动。
2026-10-15 12:27:59 +08:00
shy3130 b14f3679d5 feat(paper): 模拟盘重构 — 多账户对比与策略自动执行
- 对比榜单 14 列可排序, 盘中实时估值; 行展开完整账户操作台
- 创建即绑策略自动执行: 入场信号买入 · 出场信号全平, 支持最大持仓
  (对齐回测口径)、仓位、订单类型、冷却; 批量创建同享
- 账户删除 (两步强确认)、冻结; 回合明细; 基础配置 (新账户默认参数)
- 策略联想下拉重设计: 全量候选、两行式选项、portal 防裁剪
2026-10-14 15:11:54 +08:00
shy3130 ecb49cbaca release: v0.3.6 — 核心+扩展架构完善版
合并 0.3.6 分支全部内容 (36 提交, 详细历史见 0.3.6 分支):

■ 数据与插件
- TdxQuant 数据源: 通达信量化接入 (实时/五档/日K/复权/分钟), tdxaidata 收进默认依赖
- 扩展表两级拉取配方: 概念/行业出厂即带完整可拉配置, 可作自定义接入参考示例
- 能力门禁日志带生效源; 标的池解析只走 instruments 维表

■ 页面扩展化
- 11 个官方页面全量迁移为单文件扩展 (custom/*/extension.tsx), 删目录即卸载
- 运行时页面包系统: 打包产物上传即挂载, 免重建宿主
- 新装用户扩展页默认隐藏, 老用户升级菜单无感

■ AI
- Responses 协议接入; 会话历史与长任务跨设备同步 (服务端注册表)
- 助手头部快捷入口 + 悬浮球拖拽 zoom 坐标系修复 + 系统设置开关

■ 界面
- 设置「关于」子菜单: 版权/更新/打赏 + 开源许可弹窗与合规声明双保险
- 侧栏两态收起、数据/AI 助手快捷行 (同步呼吸光晕)、核心/扩展 ext 标记
- 界面缩放默认 90%; 菜单设置徽标 Swiss 化; 策略池「叠加」分组
- 情绪评分口径可配置; 财务画像 5 张子表手动拉取

■ 文档与其他
- README 重构「核心+扩展」主线 + 架构图重画; 开放端点数核实为 65
- 版本号 bump 0.3.6; tdx 物化库测试夹具补 macOS dylib
2026-10-13 13:40:17 +08:00
shy3130 350ffbf612 chore(build): 精简 Dockerfile 可选构建阶段, 清理文档与引导页冗余引用 2026-10-11 15:42:55 +08:00
shy3130 da51ff5711 feat(migrate): 旧数据目录一次性自动迁移 — 信号自动种入 + 失效策略自动归档
老环境升级后进入策略页逐文件报错刷屏、信号库为空, 需要用户手动搬运。
改为启动时自动完成, 前端只提示一次:

- 信号种子: data/user_data/custom_signals 为空且从未种过(.seeded_v1
  标记防重)时写入 20 个默认定义(原内置信号, 带 signal_* 列名), 写入
  即用户数据可编辑可删; 用户已有自定义信号时不掺入只落标记; 全删后
  重启不复活
- 失效策略归档: 引擎加载后把「内置残留」类失败(composite 子策略断链/
  import 已删内置模块/引用不存在的策略)移入同目录 _archive_unloadable/
  (引擎只扫顶层 *.py), 归档后 reload; 语法错误等普通失败不归档仍走
  原提示; 同名碰撞追加序号不覆盖
- 提示一次: /api/strategies 透出 legacy_migration 摘要, 前端按迁移
  指纹 localStorage 防重, 一条 toast 说明种入/归档结果

单一事实源: app/strategy/signal_seeds.py (tests/fixtures JSON 同内容,
tests/signal_seeds.py 改为从此读取)。回归: 6 个新迁移测试 + 后端 66
passed + 前端 vitest 125 + tsc 0; 本机实启验证 66 策略/0 错误/不重复
种入(标记落盘)
2026-10-10 22:15:17 +08:00
shy3130 9fdf7266a3 fix(screener): 旧数据目录升级的宽容降级 — 兼容垫片 + run_all 跳过失效 ID + 报错聚合
内置策略移除后, 老环境(策略池残留内置 ID / 自定义文件 import 旧模块 /
composite 断链)进入策略页会刷屏报错。三层修复:

- 兼容垫片: app/strategy/builtin/factor_rank_research 透明转发到
  app.strategy.research —— 旧策略文件 import 零改动继续可用
- /run_all 宽容: 混合未知 ID 跳过继续跑并回 skipped_unknown(全部未知
  才 404); 前端据此自动清策略池并提示一次, 空库场景 prune 的兜底
- 前端 load_errors toast 聚合: 多个失败合并为一条带文件名与修复指引,
  不再逐条刷屏

配套回归: tests/test_legacy_upgrade_degrade.py(垫片转发/混合跳过/全未知
404); 后端 34 passed + 前端 vitest 125 passed + tsc 0 错
2026-10-10 21:47:46 +08:00
shy3130 e077fc2729 Merge branch 'refactor/de-builtin-strategies-signals' 2026-10-10 21:30:28 +08:00
shy3130 918c7ade7e refactor(core): 策略与信号全面去内置化, 转为用户自定义定义
- 策略: 引擎只加载 data/strategies/{custom,ai,composite} 与研究模板目录,
  原 25 个内置策略一次性迁移为用户自定义文件(ID 不变, 引用零迁移);
  研究模板移至 app/strategy/research, 打包 spec 同步; 新装环境策略库为空
- 信号: 管线不再硬编码任何信号表达式; 涨跌停判定价成为运行时列
  limit_up_price/limit_down_price(生效价∓0.005 容差), 20 个信号转为
  data/user_data/custom_signals 定义(显式 column 沿用 signal_* 原列名);
  依赖解析/注入顺序/当日路径 prev-join 全部定义驱动; 语义统一为历史路径
  口径(顺带修正当日路径 BOLL 比较符与翘板/炸板空值两处既有偏差)
- 前端: 信号库单列表(全部可编辑), SignalPicker/监控选项/信号标签全走
  定义接口; 回测页新增免责声明(模拟性质/数据源准确性不作保证/不构成
  投资建议)
- 测试: 25 个策略夹具与 20 个信号种子入库 tests/fixtures, 受影响测试
  全部自包含化(不依赖运行目录用户数据); 77 万行 MA 死叉新旧表达式对拍
  逐行一致; 回测实跑 45 笔卖点信号出场验证矩阵链路
- 同批包含工作区既有进度: 策略结果 ext 列同日投影修复(含测试)、数据源插件、fuyao/auth/api_gateway/data_integrity 调整、README 信号库
  描述与 strategy.md 导入路径补充

验证: 后端 2592 passed(空数据目录 CI 模拟 2588 passed, 4 例为模拟环境
伪影复验排除); 前端 vitest 125 passed + tsc 0 错 + vite build 通过
2026-10-10 21:10:44 +08:00
shy3130 ae9feb869c fix(sources): 自定义源全量分钟/分钟K amount 改为可选 + 保存先验后存
amount 按契约可空, 缺成交额的源此前被整体拒绝且保存静默失败;
现在校验不过返回 400 带原因, 不落盘。
2026-10-09 16:21:29 +08:00
shy3130 b65d2691d9 feat(strategy): 每策略「叠加条件」overlay_filter — 零代码硬过滤叠加
策略设置新增「叠加条件」分区: 字段+运算符+值 多行 AND 硬过滤, 直接叠加在
策略自身规则之上, 选股/回测/监控三处一致生效, 不改策略代码、无需另建
信号或叠加策略 (扩展数据因子如 ext_ext_fuyao_hot_rank 可直接选)。

- 条件结构与自定义信号同源 (allowed_fields 白名单含注册表因子/字符串扩展
  字段), 禁用日期偏移, 最多 8 条
- 只挡入场/候选: exit_signal_hits 在过滤前收集, 已持仓卖出不受影响
  (与 basic_filter 既有口径一致)
- null/缺数据 ≡ 不命中 (fail-closed); 引用列缺失时报可读错误
- 仅日线 polars_expr/matrix_native 支持, composite/minute 保存期+运行期双拦;
  matrix 路径拒绝字符串字段 (矩阵 fields 为 float 数组)
- 保存时条件实际变化才清策略结果缓存, 普通保存不受波及
- 回测: polars 路径在裁剪前完整 panel 上评估掩码 AND 入场; matrix 路径条件
  字段并入 feature_plan 进矩阵 fields, NaN 一律不命中
- 前端提取 ConditionEditor 共享组件, 自定义信号弹窗复用 (净减 ~240 行)

测试: 后端新增 16 项 + 回测/关联模块回归全绿; ruff 对比基线零新增;
前端 6 项组件测试 + tsc/vite build 通过。
2026-10-09 00:19:59 +08:00
JackChan83andJackChan83 e15fff13c1 fix(regime): _score 对非有限输入取中性 50(上游缺此防护,移植本机 f67d9ed 的防护) (#455)
问题(本机 2026-09-15 实测事故;上游同名表达式逐字相同):
  停牌股补零 ⇒ change_pct = close / prev_close - 1 = inf ⇒ 当日 avg_pct 被单个 inf 污染
  ⇒ _score 里 round((value - low) / (high - low) * 100) 抛
    OverflowError: cannot convert float infinity to integer
  —— round 是**最内层**调用,在 min/max 钳制**之前**求值,钳制救不了它
  ⇒ compute_regime 整段中止、regime_history 停更。上游原先没有覆盖该路径的测试。

改动(三处逐字副本,+15 行,无 schema 变更、无数据迁移):
  - app/services/regime_builder.py:新增 `import math` + `_score` 非有限值取中性 50.0
  - app/services/market_overview_builder.py:同款防护(math 已在 import 中)
  - app/api/overview.py:同款防护(math 已在 import 中)
  - tests/test_regime_score_non_finite.py:新增 3 例(_score 单元 / classify_state / _aggregate_daily 端到端)
  取 50 = 「该维度不可计算」:既不崩,也不把 inf 钳成 100(那等于伪造「极度看多」)。

验证(P1 先红后绿;全部在 origin/main 隔离 worktree 内执行):
  - P1 红:**未改代码**上 pytest tests/test_regime_score_non_finite.py → 3 failed,
    报错与生产逐字一致(OverflowError: cannot convert float infinity to integer)
  - P2 绿:修后同命令 → 3 passed
  - P3 行为:三处 `_score(nan / inf / -inf, -1.2, 1.3)` 全部 = 50;
    常规值 `_score(0.5, -1.2, 1.3)` 三处仍 = 68.0 ⇒ 正常口径未漂移
  - P4 基线:tests/test_regime_builder.py → 22 passed(与改动前一致)
  - P5 lint:ruff 三个改动文件 + 新测试 → 有改动 24 / stash 回上游原状 24 ⇒ **0 新增**;
    `git diff --check` rc=0
  - P6 相关回归:引用这三个模块的既有 5 个测试文件 → 35 passed
  - P7 逐字一致:三处 hunk 与本机 f67d9ed 的同名 hunk 完全相同(仅行号因上游位移);
    新增测试与本机 f67d9ed 版仅差 docstring 中一句(见下「边界」)

边界(本移植**未**包含):
  本机同批修复里「上游 `change_pct` 对非正前收取 NULL」(`ratio_over_positive`,
  app/indicators/pipeline.py)及 tests/test_pipeline_price_ratio.py 未移植
  ⇒ 本件只堵「坏值已产生后不崩」,**不堵「坏值的产生」**。
  ⚠️ 自动测试通过 ≠ 上游真实数据上不会再出现非有限值 ⇒ 仍需**上游真实运行**验证;
  本提交是把本机已验证的防护**预置**过去,不是对上游线上事故的结论。

影响与回滚:
  仅改计算口径(非有限输入的去向),无 API 形状 / schema / 数据迁移变更,历史 Parquet 不受影响。
  `git revert <sha>` 即可回滚。
  本提交在基于 origin/main(30fcade) 的隔离 worktree 内完成,本机主线工作树未被改动(status 为空)。

Co-authored-by: JackChan83 <JackChan83@users.noreply.github.com>
2026-10-08 13:08:41 +08:00
shy3130 f17260587b fix(watchlist): 分时缩略图续画按资产类型行情日期守卫, ETF 旧价不再拼尾K
enriched 响应新增 dates; 未开实时拉取的资产类型 (enriched close 为旧日K回退值)
不续画, 修复自选页 ETF 分时尾部错价长刺。
2026-10-08 12:04:41 +08:00
shy3130 badab07619 feat(adj): 除权因子独立同步 + 事件明细扩列 + 按需窗口优化
- 扩列: adj_factor 表扩至 8 列(dividend/bonus/allot/allot_price/prev_close 明细, 可空), fuyao 从事件 dump 原始成分回填; merge 变更检测按 ex_factor diff>1e-9, 仅明细回填不计入受影响列表; 字段说明补齐
- 独立同步: /api/pipeline/adj-factor/run 端点(共用任务机制: 单飞+重任务槽+行情暂停), Data 页除权因子卡片设置齿轮弹窗(生效数据源/能力徽标/TickFlow 无明细提示), 因子变更个股自动 enriched 局部重算
- 按需优化: 独立同步事件窗口钳到本地日K起点(更早事件在前复权 cum/total 两侧抵消, 对已存价格零影响); fuyao 配价由全有或全无改为逐只按需(远古事件只拖累自己, 不再整轮回退单标的接口); 实测全市场因子阶段 15min+ → ~11s, 配价 3676/3676 走本地 dump 零回退
- 盘后管道步骤条显示各能力路由徽标(矩阵驱动); README 补桌面端 macOS 安装注意事项
- 测试: 明细列 merge 语义 4 例 / 独立同步联动 5 例 / 远古事件不连累全场回归; 全量回归通过(2 例历史遗留失败与本改动无关, 基线同样失败)
2026-10-07 21:45:40 +08:00
shy3130 4ba0c9bcc0 修复部分已知Bug 2026-10-06 12:40:16 +08:00
shy3130 379b7d283a feat(paper): 对比视图二期 — 全面去擂台化措辞 + 行内嵌完整账户面板替代跳转
- 措辞: 擂台/参赛/比拼全部改为对比定位 (标题/按钮/卡片/测试/端点文案), 移除 Trophy/Swords 图标
- 交互: 删除「进入」按钮, 点行展开内嵌 AccountPanel (下单/跟单/费用/冻结/持仓/台账/净值/策略对比), 单账户视图仅保留新建向导
- compare 增量字段: created_at/last_nav_date/day_change_pct/auto_rules/auto_enabled/holdings_count (加法契约)

验证: pytest 全量 2485 passed 6 skipped; ruff 通过; pnpm build 通过; 浏览器实测展开面板无擂台字样、无跳转、布局正常
2026-10-04 22:11:55 +08:00
shy3130 ca30bdaa84 feat(paper): 模拟盘擂台主视图 — 多账户收益对比榜单 + 同规格批量创建
参考擂台模式重构模拟盘默认视图, 对比从弹窗提升为页面主形态;
数据层零改动, 老账户自动上榜, 原单账户记账功能全量保留为下钻视图。

后端 (加法契约):
- POST /api/paper/arena/batch_create: 同本金/同费率一次开 N 个账户
  (≤20, 服务端生成 arena_ id), 各绑一条自动跟单规则; 规则整体先校验
  再落盘, 任一非法 400 不留半创建状态
- GET /api/paper/compare 增量字段: holdings_count / created_at /
  last_nav_date / day_change_pct(末两定版净值) / auto_rules / auto_enabled,
  旧前端可忽略
- 开放契约快照 +1 端点 (test_openapi_contract)

前端:
- Paper.tsx 拆为 ArenaView(默认: 摘要卡 + 归一化净值叠加 + 收益降序
  榜单[排名/徽章/迷你走势/跟单规则chip] + 行展开持仓与近期成交) 与
  AccountView(原视图全量保留, 头部加返回擂台); compare 查询 60s 轻轮询
- ArenaCreateModal: 策略/监控规则联想添加 + 全部策略一键加入(≤20),
  方向/仓位/订单类型/冷却为全表共享参数保证同规格
- api.ts: PaperCompareRow 扩展可选擂台字段 + PaperArenaSource 类型
  与 paperArenaCreate; 查询键复用 paperCompare/paperAll

验证: 全量 pytest 2485 passed (含新增 test_paper_arena 4 用例);
ruff 通过; pnpm build 通过; 浏览器实测擂台渲染/行展开/下钻返回/
批量创建弹窗交互均正常 (未在真实数据目录实际建账户)
2026-10-04 22:01:59 +08:00
shy3130 44e8b7ebbd feat(dashboard): 布局后端持久化(preferences链路) + 外部链接组件(sandbox iframe+新窗口兜底) + 添加组件面板 + useDashboardLayout持久化hook(7用例) 2026-09-26 20:52:04 +08:00
shy3130 f5d9d6af71 feat(assistant): 工具轮次检查点支持在设置→AI 手动配置 (默认100, 0=不检查, 最小5) 2026-09-26 19:04:54 +08:00
shy3130 1d855de03b feat(assistant): 数据完整性与补全 — check_data_coverage 只读检查 + sync_data 确认闸门 + get_sync_status 进度
- check_data_coverage: 分区目录轻量扫描(与 /api/data/status 同口径, 不读
  parquet)输出日线/enriched/分钟K覆盖区间、财务表覆盖、进行中任务与 issues
  问题清单(数据停更/指标落后/财务缺失); 可选 symbol 参数查单标的日线+财务
- sync_data(动作, 须确认): 复用数据页同一条触发路径 — pipeline 盘后管道 /
  financials 财务表调度器 / minute_extend 分钟K向前扩展(days 钳制 30-1095);
  后台执行立即返回, 单飞去重, async 工具经事件循环调度后台任务
- 核心层最小抽取: api/pipeline.trigger_pipeline_job 与
  api/kline.trigger_minute_sync, HTTP 端点与助手共用(端点行为不变)
- get_sync_status: 活跃任务阶段/进度 + 最近 5 任务 + 财务同步状态
- 提示词/快捷指令(数据是最新的吗)/前端足迹标签同步补齐
- 测试: +7 项(覆盖检查缺口与新鲜数据/单标的滞后/共用触发路径与钳制/
  财务同步与参数校验/闸门拒绝不触发/摘要), 助手套件 21+34 项通过;
  全套 2428 passed(1 项 backtest spawn 时序 flake 单独重跑通过);
  线上 mock 验收: 真实数据发现缺口 → 建议补全 → 确认卡 → 拒绝不触发
2026-09-26 15:09:10 +08:00
shy3130 f20772d7b7 feat(open-api): 开放能力闭环 — write:ext 数据写入 + SSE 事件流 + 契约守护
二开闭环补齐三块: 数据进得来 (写入)、事件推得出 (SSE)、契约有人守 (快照+CI)。

- write:ext scope (第六档): POST /api/ext-data/{id}/ingest 对 Token 开放,
  复用管理端同一校验/落盘/视图刷新路径; 结构配置/上传/拉取仍不开放,
  外部只能写行数据, 不能改写表结构
- SSE 短期票据 (V2 收尾): POST /api/events/ticket 换 60s 一次性票据 →
  GET /api/events?ticket=… 订阅事件流; 票据只继承 Token scope 不放大权限;
  进程内事件总线 (services/events.py, 慢消费者丢旧保新), 告警落盘点已挂
  (alert_store.append/append_many → bus), 事件按 scope 过滤双向验证
- 契约守护: test_openapi_contract.py 冻结 tier=a 开放面 (61 端点),
  增删须显式更新快照; 新增 ci.yml (后端全量测试 + 前端构建) 把契约
  变化拦在 PR 上
- examples/open-api: 四个零依赖可运行示例 (行情/写入/回测/事件流) + README
- 菜单设置架构标注: 每页核心/扩展徽标 + 悬停原因 + 图例 (按 open-platform-plan
  §2 依赖方向分类, 核心 8 页/扩展 11 页); 顺带补上 MenuSettings 缺失的 模拟盘
- 测试: 网关 write矩阵/票据语义 + 票据生命周期/总线/SSE帧/告警联动 + 契约快照,
  全量 2408 passed / 102s; 线上实测: ingest 200 / 票据一次性 / SSE hello+
  alert 推送 / scope 过滤双向 / 契约 61 路径
2026-09-26 11:31:11 +08:00
shy3130 7f628816b9 feat(open-api): 0.3.2 开放能力版 — API Token 网关 + Tier A 契约 + 版本清单
- Token 域模块: tsp_ 前缀 + SHA-256 哈希存储 (0600), 明文仅创建时返回一次,
  吊销立即生效, last_used_at 节流落盘 (≥60s)
- Bearer 网关中间件 (与密码会话并行): 五档 scope 校验 (read:market/read:ext/
  read:analysis/run:backtest/paper:trade) + 滑动窗口限流 (默认 120/min,
  OPEN_API_RATE_LIMIT_PER_MIN 可调) + X-RateLimit 响应头; 管理接口永不对 Token 开放
- GET /api/openapi.json?tier=a 契约视图: 按网关规则表过滤 OpenAPI 规范 (58 路径),
  规则表即唯一契约源
- 设置 → 开放接口: Token 管理 UI (创建表单/scope 说明/明文一次性展示/吊销)
- 设置 → 系统设置 检查更新: 静态链接升级为真实版本对比 (GitHub API 优先,
  latest.json 清单兜底), 发现新版本给下载入口
- release.yml 新增 manifest job: Release 附 latest.json (版本/三平台下载地址/sha256),
  支持分批发布按实际资产生成
- 版本 0.3.1 → 0.3.2 (后端 __init__/pyproject + 前端 package.json)
- docs: features.md 开放接口章节; open-platform-plan.md V1/V2 标记已实现
- 测试: test_api_gateway.py 8 项 (域模块/scope 映射/E2E 401-403-200 矩阵/
  429+Retry-After/吊销即拒), 全量 2394 通过
2026-09-25 22:38:58 +08:00
shy3130 5f39f7dd8d feat(ext-data): 数据出口强化 + 核心开放设计方案 (0.3.2 起点)
- /rows 查询五件套: filter 等值过滤 / sort / offset 分页 /
  start_date+end_date 范围合并 (自动补行级 date 列, diagonal 容忍分区
  schema 漂移), 快照模式范围查询明确 400
- /values 字段取值枚举端点 (filter 下拉配套, 去重+计数降序)
- 市场级表 (market_level): 行=全市场每日一条, 无标的列; 创建/更新 API、
  ingest 与拉取链路放行、创建向导开关跳过标的关联 —— 市场环境类数据
  发布为扩展数据的底座
- 拉取分页协议 (仅 GET): page_param/page_size_param/page_size/max_pages,
  空页/短页判停; 拉取面板新增分页配置输入
- docs: features.md 分页与 /rows 契约章节; open-platform-plan.md
  核心能力开放与插件化改造设计稿 (Token/scope/限流/Tier A/分期路线)
- tests: 22 个新用例 (查询语义/分页判停/市场级全链路/values),
  ext 全量 261 通过
2026-09-25 21:29:23 +08:00
shy3130 252160e46f feat(paper): 账户横向对比/费用可调/默认值记忆/下单与策略ID联想 + 界面美化
- 横向对比: 新增 GET /api/paper/compare (逐账户概览+回合统计+定版净值);
  前端「账户对比」弹窗 — 归一化净值叠加图 (起点=1) + 12 项指标对比表,
  收益领先账户标「领先」徽标, 冻结账户标「冻结」
- 费用可调: update_settings 扩展佣金/印花税/滑点三参数 (范围校验,
  仅影响之后的新成交); 头部费用文本改为可点击按钮, 弹窗内与涨跌停排队一起改
- 默认值记忆: 创建账户表单新增费用三输入框, 本次取值存 localStorage
  作为下次新建的预填默认
- 联想搜索: 下单代码接 instrumentSearch (代码/中文名/拼音首字母, stock+etf);
  自动跟单策略/规则 ID 输入框按中文名/ID 过滤, 聚焦出全量列表;
  抽出通用紧凑联想组件 SuggestInput (键盘导航/外点关闭)
- 美化: 统计卡带主题色图标 (盈亏图标随涨跌变色), 悬停强调边框
- tests: settings 费用更新 (含超范围 400) 与 compare 契约 2 个新用例 (51 passed)
2026-09-25 16:21:24 +08:00
shy3130 dbb2e6dd14 feat(paper): 模拟盘虚拟账户 — 模拟撮合/自动跟单/多账户/涨跌停排队/统计告警
- 撮合域: append-only 成交台账唯一事实源, T+1/涨跌停/停牌顺延/除权调整,
  佣金印花税滑点与回测引擎同口径
- 下单: 即时/次日开盘/当日收盘, 盘中快照撮合 + 盘后结算幂等;
  涨跌停排队次日重试可选 (账户级开关, 顺延上限 3 日)
- 自动跟单: 监控事件触发按规则下单 (跟策略/跟规则, 固定金额/权益%,
  同标的冷却去重), 下单复用撮合域同一把锁与校验
- 多账户: data/paper/accounts/{id}/ 完全隔离, 旧单账户布局自动迁移,
  API ?account= 贯穿全部端点, 盘中钩子与盘后结算逐账户执行
- 统计: FIFO 回合/胜率/盈亏比/均持天数/最大回撤; 成交落告警记录
- 前端: 模拟盘页 (净值对比沪深300/持仓/订单/成交台账/下单/规则面板/
  账户切换), 买入红卖出绿 A 股配色
- 测试: 域模块 33 项 + API 契约 8 项
2026-09-24 17:19:09 +08:00
shy3130 c37f450e28 feat: 更新 README, 新增快速预设, 调整 AI 默认上下文/输出限制
README:
- 更新顶部说明区块, 新增静态展示资源

快速预设 (设置页):
- 新增预设项, 调整官网链接与介绍文案, 高亮样式适配明暗主题
- 模型输入框支持下拉选择: 经后端代理拉取模型列表, 支持关键词过滤

AI 默认配置:
- 输出上限 8192 → 16384, 上下文窗口 64000 → 128000, 对齐当前主流模型能力
- 后端新增模型列表代理接口, 前端 api 同步封装
2026-09-24 11:39:54 +08:00
kevin9327 56eab07723 fix(monitor): 误存为 stock 的 ETF 规则改走 ETF 监控轮 2026-09-23 20:01:22 +09:00
kevin9327 bd85d56cae fix(stock-analysis): 个股分析与关键价位日K窗口改用北京日期
助手工具 get_stock_daily / get_stock_analysis 已用 cn_today(),
个股分析页的 _load_kline 与 GET /levels 仍走 date.today()。
美西主机整个 A 股交易时段、UTC 主机北京 00:00-08:00, 本地日历日
比北京早一天, 管道已写入的当日官方 K 被排除, 分析与价位停在昨天。

Closes #390
2026-09-23 07:44:29 +09:00
shy3130 b6a7367262 feat(screener): 新建策略「默认基础参数」配置与一键应用全部策略
- 策略页头部新增配置入口: 编辑默认基础过滤(价格/流通市值/成交额/换手/板块/ST), localStorage 持久化, 内置默认与原模板一致
- 新建策略两条路径生效: 自定义/matrix 模板注入 + AI 生成 step1 提示词注入(未配置时提示词逐字节不变)
- 对话框内一键应用: 二次确认后分批 PATCH 到全部股票策略, 只动 basic_filter 不碰各策略参数/评分, 应用即所见并同步存为默认配置
2026-09-21 13:46:32 +08:00
wshy 46e1513f88 Merge pull request #384 from kevin9327/fix/kline-gzip-nonfinite-json
fix(kline): gzip 传输层剔除 nan/inf, 避免写出非法 JSON
2026-09-21 07:42:31 +08:00
wshy a75feef210 Merge pull request #380 from kevin9327/fix/index-daily-end-beijing
fix(index): 指数日K默认截止日期改用北京日期, 缓存冷时不再丢当日K
2026-09-21 07:42:09 +08:00
wshy 33b83b862c Merge pull request #378 from kevin9327/fix/kline-daily-end-beijing
fix(kline): 个股日K默认截止日期改用北京日期, 缓存冷时不再丢当日K
2026-09-21 07:41:58 +08:00
kevin9327 cfef4b633e fix(kline): gzip 传输层剔除 nan/inf, 避免写出非法 JSON 2026-09-20 20:10:12 +09:00
kevin9327 9392735b01 fix(index): 指数日K默认截止日期改用北京日期, 缓存冷时不再丢当日K 2026-09-20 20:01:27 +09:00
kevin9327 15bafb0eef fix(kline): 个股日K默认截止日期改用北京日期, 缓存冷时不再丢当日K 2026-09-20 19:59:20 +09:00
kevin9327 7258e432a3 fix(kline): 自选迷你K默认截止日改用北京日期, 盘中不再丢当日K 2026-09-20 19:55:02 +09:00
shy3130 72fc28d813 merge: main (解决 test_kline_daily_latest 追加冲突, 保留双方用例)
并按 #369 后的 cn_today 守卫钉死 test_index_daily_live 的日期,
消除非 CST 主机北京 00:00-08:00 的测试闪失
2026-09-20 16:43:08 +08:00
wshy b383cb965b Merge pull request #369 from kevin9327/fix/kline-live-candle-beijing
fix(kline): 当日实时K注入按北京日期判定, UTC 主机盘中不再丢K
2026-09-20 16:39:36 +08:00
shy3130 5fad0da469 fix(kline): 新股上市初期无涨跌幅窗口判定, 修复分时钳制与假涨停信号
注册制新股上市前 5 个交易日 (北交所仅首日) 无涨跌幅限制, 此前系统
完全没有该概念 (C沈鼓 601091.SH 09-18 昨收 20.8/盘中 82.59):

- 分时图: 自适应模式不再钳制到 ±rate 涨跌停带内 (y 轴被夹在
  18.72~22.88, 曲线全部出界); 涨跌停模式取涨跌停带与实际数据较大者;
  上市首日无昨收时 yAxis 加 scale 不再从 0 锚定; 区间过宽时刻度减半
- price_limits: 新增窗口判定单一事实源 (注册制改革分板块 cutoff,
  is_no_limit_day 交易日序号精确门控 + 保守日历边际兜底)
- pipeline: _no_price_limit 由「哨兵值且 as_of 命中单日」扩展为
  「或 listing_date 命中窗口」; 连板/炸板/翘板/回测撮合约束全部继承;
  实时路径同口径兜底
- api: minute 响应 price_limit 新增 no_limit, 前端据此不画假涨跌停虚线
- schemas: list_date → listing_date 命名对齐 (与维表实际字段一致)

测试: 窗口日/第 6 日恢复/北交所首日/实时路径/API no_limit/前端 y 轴
范围/普通股与 ST 回归; 后端全量 2237 passed, 前端 43 passed。
2026-09-20 16:07:07 +08:00
kevin9327 51b39fd78c fix(kline): 指数日K盘中注入当日实时蜡烛, 与股票/ETF 同口径 2026-09-20 16:56:05 +09:00
kevin9327 96c8eb1851 fix(kline): 钉死日K测试的 cn_today, 修正守卫注释时区归因
既有 daily/latest 测试用 date.today() 构造 fixture, 守卫改用 cn_today() 后
在本地日期不等于北京日期的主机上会误判为过期缓存。与新增测试同法钉死日期,
使整个文件跨时区确定。同步修正注释: 盘中丢K是美洲时区, UTC 主机旧症状是
昨日残留注入。
2026-09-20 16:54:51 +09:00
kevin9327 4a04b15a83 fix(kline): 当日实时K注入按北京日期判定, UTC 主机盘中不再丢K 2026-09-20 16:46:59 +09:00
shy3130 4efc238032 feat(kline): 分钟K原始口径落盘+共享复权因子表, 读取时即时前复权投影
解决除权后已落盘分钟数据(前复权口径)与最新数据不可比的问题:
- 新增 minute_adjust 服务: 除权因子表 + 读取路径投影, ratio =
  cum_factor(D)/total_factor 作用于价格与成交额, ratio=1 短路直读
- kline_sync/repository: 数据目录存在 .raw_basis 标记时分钟拉取改用
  adjust='none' 落盘原始 OHLC; 无标记保持旧前复权行为, 字节级兼容
- api/kline: 新增 POST /api/kline/minute-migrate 幂等迁移, 将混合口径
  分区转为原始口径后写入标记启用新架构
- 测试: 新增 test_minute_adjust (9 例); 5 个既有分钟测试适配新口径

全量后端测试通过 (2239 passed, 1 例既有偶发 flaky 与本次无关)。
2026-09-20 14:23:33 +08:00
richardandClaude 5123274fb0 feat(watchlist): 新增「加入日期」「加入以来」两列与日K加入自选日标注
自选 parquet 一直记着 added_at, 但前端从未消费过, 用户看不到加入时间也算不出加入以来收益。
本次在 /api/watchlist/enriched 读时计算并下发 (与涨跌停价同属现算、不落盘):

- added_at 原样透传 (naive UTC), 前端按 UTC 解析后转北京时间展示
- pct_since_added 以「加入日或之前最近交易日」的前复权收盘价为基准, 小数口径 (与 momentum_*
  一致); 超出内存历史缓存窗口 (约 300 自然日) 与 ETF/指数显式降级为 null —— 该端点位于
  SSE 行情失效前缀, 每几秒被重拉一次, 故不做逐只 scan 兜底
- 新增 KlineRepository.get_enriched_history_span(): 纯读 O(1), 用于区分「预热中」与「日期超窗」
  (get_enriched_range 对两者都返回 None)

前端两列默认隐藏 (自定义列 → 自选分组); K线弹窗日K主图用 custom series 画蓝色竖虚线 +
带框「自选」标签, 从该根K线下沿连到网格底边, 缩放后自动重绘, 工具栏提供独立开关。
日期不在可视区间 / 周末节假日加入时竖线不画 (不做 snap), 由工具栏文字兜底。

验证: 后端定向 pytest 45 passed, ruff 相对改动前基线零新增; 前端 pnpm build 通过, vitest 20 passed

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-19 16:35:26 +08:00
shy3130 51be43e951 feat(watchlist): 自选页新增 今开/最高/最低/昨收/成交量/涨停价/跌停价 列 (#328)
- open/high/low 后端本就返回, 纯前端加列; prev_close/volume 在 enriched
  缓存已有, _WATCHLIST_COLS 白名单补 2 字符串即透传, 零新增 IO
- 涨跌停价在端点内对自选行(几十~几百行)用 polars_price_limit_pct +
  polars_limit_price 向量化现算(交易所整数分半进位口径, 含主板 ST
  2026-07-06 新老划断), 亚毫秒级; ETF/指数涨跌幅规则不在覆盖范围内,
  置 null 由前端渲染 "—"
- 前端 7 列默认隐藏(未开启用户零渲染/排序成本), mergeColumns 对老用户
  持久化配置自动补齐新列, renderBuiltinDataCell/getSortValue 各加 7 case,
  支持排序与数值筛选; 涨停价红色/跌停价绿色, 成交量按万手/亿手换算
- 测试: watchlist_enriched 契约(含 ST 划断前后两种数据日) + mergeColumns
  老配置兼容(vitest)
2026-09-17 16:04:25 +08:00
wshy 77603a5be1 Merge pull request #325 from kevin9327/fix/factor-trial-nan-ic
fix(factors): 公式试算剔除截面值全相同日的 NaN IC, IC 均值与胜率不再失真
2026-09-17 08:24:24 +08:00
kevin9327andClaude Opus 5 02b4be974b fix(factors): 公式试算剔除截面值全相同日的 NaN IC, IC 均值与胜率不再失真
/api/factors/trial 按日算截面 Rank IC 后只滤 null。某天截面上公式值全部相同
(离散公式常见, 如 ETF 池里 if_else(change_pct > 0.05, 1, 0) 当天无标的满足)
时 pl.corr 返回 NaN 而不是 null, 于是:

- IC 均值/标准差/IR 被这一个截面污染成 NaN, 响应里为 null, 页面显示为空;
- 胜率 (ic > 0).mean() 把 NaN 计为正 IC (polars 中 NaN > 0 为真);
- n_dates 与 ic_series 计入无定义截面。

因子检验 FactorBacktestService._evaluate_panel (valid_ic_df)、IC 衰减与挖掘指标都已按
is_not_null() & is_finite() 剔除, 试算对齐同一口径。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 20:11:24 +09:00
wshy 3deeccf8d8 Merge pull request #322 from kevin9327/fix/minute-lunch-expected-bars
fix(kline): 午休 11:31-12:00 的期望分钟根数封顶 120, 本地完整上午不再判为不完整
2026-09-16 18:44:11 +08:00
kevin9327andClaude Opus 5 88ac0403eb fix(kline): 午休 11:31-12:00 的期望分钟根数封顶 120, 本地完整上午不再判为不完整
/api/kline/minute 与 /api/kline/minute-batch 按北京时刻估算当日应有的分钟K
根数, 本地够数就用本地, 不够才实时拉取。上午分支条件写成
h < 12 or (h == 12 and m == 0), 11:31-12:00 仍按 (h - 9) * 60 + m - 30 增长到
121..150, 而上午只有 120 根 (09:31-11:30)。

- /minute: 11:44 起 120 < 0.9 * expected, 本地完整的上午被判不完整, 转去
  fetch_minute_single; 拉空时返回 rows=[] / source="none", 前端
  minuteRefetchInterval 见 source="none" 停止轮询, 详情分时图空白到重新打开。
- /minute-batch: 11:33 起 120 < expected - 2, 自选标的全部归入「尾部落后」,
  每轮发起增量补拉; 补拉为空时该标的不出现在响应里。

上午分支改为截止 11:30, 午休由下一分支给 120, 与
market_time.trading_minutes_elapsed_from_dt 的「午休保持上午累计」同口径。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 19:33:33 +09:00
kevin9327andClaude Opus 5 ddb28fa02a fix(strategy): 策略生成流的心跳行补换行, 不再吞掉首个 delta 与 result 事件
5473908 给 5 个 NDJSON 流式端点接入 with_heartbeat。复盘/个股/财务/轮动
四处的事件行不带换行, 由外层 stream_gen 统一补 "\n"; 策略生成
/api/strategies/build/stream 的 event_generator 事件行自带 "\n", 直接交给
with_heartbeat, 而心跳插入的 {"type": "ping"} 不带换行, 于是 ping 与下一个
事件粘成一行, 如 {"type": "ping"}{"type": "result", ...}。

前端 strategyBuildStream 按 "\n" 切行后 JSON.parse, 解析失败静默跳过:
LLM 首包前空闲超过 15 秒时首个 delta 丢失; 结构修复 (repair_code) 超过
15 秒时 result 丢失, 界面报「AI 未返回策略结果」。

对齐另外四个端点的口径: 事件行去掉换行, 外层 stream_gen 统一补换行。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 19:21:00 +09:00
wshy d1575e0495 Merge pull request #315 from kevin9327/fix/minute-holiday-fallback
fix(kline): 个股分时与自选分时的缺省日期在工作日休市时回退到最近交易日
2026-09-16 09:43:39 +08:00