shy3130
1e38c8cebb
fix: reset strategy builder identity
2026-07-16 16:12:06 +08:00
shy3130
c763a6970f
fix: restore strategy and data compatibility
2026-07-16 14:34:07 +08:00
wshy
c5049d26a7
Merge pull request #130 from lytem28/feat-matrix-pr
...
feat: 大幅优化回测速度以及内存占用
2026-07-16 13:25:44 +08:00
lytem28
b6cf0495e1
feat: complete matrix-native backtest engine
...
Unify strategy execution across backtest, screener, and monitoring; isolate backtest workloads in spawn workers; and add shared matrix caching plus valid-bar indicator acceleration.
2026-07-16 12:17:27 +08:00
wshy
b1845cf491
Merge pull request #129 from CJ0Hn/feat/watchlist-screenshot-import
...
feat(watchlist): 支持从券商自选截图批量导入
2026-07-16 00:03:18 +08:00
ChenJunheng
0d6b341945
fix(watchlist): 采纳 #94 审查 — 防大图 OOM、OCR 不阻塞事件循环、收紧图片类型
...
为截图预处理增加像素上限与长边降采样;import-image 将 OCR 放入线程池;
去掉任意 image/* 放行,仅允许白名单 MIME/扩展名。
2026-07-15 23:28:30 +08:00
ChenJunheng
6f084e1b29
feat(watchlist): 支持从券商自选截图批量导入
...
基于 Tesseract OCR 识别六位代码并校验证券主数据,前端提供导入确认弹窗;
修复批量添加后 enriched 缓存未刷新导致需手动刷新页面的问题。
2026-07-15 23:25:46 +08:00
shy3130
77876c7ee4
fix(data): avoid destructive enriched rebuild cleanup
2026-07-15 21:34:44 +08:00
shy3130
0b3b769ca8
fix(strategy): clear saved strategy drafts
2026-07-15 20:51:07 +08:00
shy3130
f317377bef
fix(strategy): apply saved params to builtin screeners
2026-07-15 20:06:11 +08:00
shy3130
89115e6f73
fix(strategy): apply saved parameters during execution
2026-07-15 19:03:48 +08:00
wshy and shy3130
963092384f
fix(capabilities): 自定义分钟数据源补 KLINE_MINUTE_BATCH 能力 ( #126 )
...
issue #121 : 用户配了自定义分钟数据源, 但分时图/自动同步/回测等功能
仍提示"需 Pro+"。根因: 能力探测(detect_capabilities)只探测 TickFlow
API Key 档位, 不感知用户本地配的自定义数据源。
修复:
- capabilities.py: CapabilitySet 加 grant() 方法 (不覆盖已有能力)
- policy.py: detect_capabilities 拆成 _detect_tickflow_caps (原逻辑不动)
+ _augment_custom_sources (探测完检查自定义分钟源, 有的话补能力)
补能力后所有 capset.has(KLINE_MINUTE_BATCH) 检查自动通过; 取数函数
内部仍按 preferences.get_minute_data_provider() 分流到自定义源,
不会错误调用 TickFlow。前端读后端返回的 capabilities, 无需改动。
Co-authored-by: shy3130 <shy3130@users.noreply.github.com >
2026-07-14 22:27:03 +08:00
wshy and shy3130
e456d018fc
feat(strategy): AI生成/自定义编写 tab 加策略开发指南链接 ( #125 )
...
两个 tab 的描述行都加了指向 GitHub strategy-guide.md 的链接,
方便用户参考指标列/信号列/filter_history 写法/参数类型等。
Co-authored-by: shy3130 <shy3130@users.noreply.github.com >
2026-07-14 21:59:56 +08:00
wshy and shy3130
ee17261feb
fix(strategy): parsePyValue 对非 JSON 值兜底, 修复 AI 修改 date 参数崩溃 ( #124 )
...
get() 对字符串值去外层引号后传给 parsePyValue, 字符串型 default
(如 date 类型的 "2024-01-01") 去引号变成 2024-01-01, JSON.parse
在 position 4 报错 → 整个 StrategyBuilderDialog 白屏。
parsePyValue 加 try/catch: JSON.parse 失败时返回原始字符串。
数字/布尔不受影响, 字符串值兜底为字符串。
Co-authored-by: shy3130 <shy3130@users.noreply.github.com >
2026-07-14 21:52:24 +08:00
wshy and shy3130
2f762b3bcc
fix(strategy): import 白名单加 datetime + date 参数处理补进文档 ( #123 )
...
问题: ai_single_yang_unbroken 策略用 from datetime import date 做
date 类型参数转换, 被安全修复的 import 白名单(只允许 polars)拦截,
策略加载失败消失。同时 date 列(Polars Date)与字符串参数直接比较
报 InvalidOperationError 导致 500。
修复:
- ai_generator.py: import 白名单加入 datetime (纯日期运算, 无文件/
网络/进程能力, 安全)。验证 os/sys/subprocess 仍被拦。
- strategy-guide.md: params type 补全(float/int/bool/select/date);
filter_history 要点新增 date 参数必须 fromisoformat 转换的代码示例
- strategy-guide-compact.md: 同步补充 (AI 运行时实际用的文档)
从源头避免 AI 生成的 date 类型参数策略再犯字符串 vs Date 列比较错误。
Co-authored-by: shy3130 <shy3130@users.noreply.github.com >
2026-07-14 21:47:26 +08:00
wshy and shy3130
f470e46f2b
fix(security): 策略代码 RCE 漏洞三层修复 ( #122 )
...
漏洞链 (安全研究员 Aeon 报告):
1. StrategyCodeSaveRequest.strict 由客户端控制, 传 false 完全跳过安全校验
2. AST 名单只拦 ast.Name 直接调用, dunder 遍历可绕过
((lambda:0).__globals__["__builtins__"]["__import__"]("os"))
3. _load_file 用 exec_module 执行策略文件, 执行侧零校验
=> 未认证局域网用户可写入任意代码并立即执行 (RCE)
修复:
- strategy.py: 移除 strict 字段, 安全校验无条件执行 (第1层)
- ai_generator.py: _validate_safety 加固, 拦截 dunder 属性访问
(__globals__/__builtins__/__class__/__subclasses__ 等) 和字符串下标
访问 (第2层)
- engine.py: _load_file 在 exec_module 前读文件内容跑一次 _validate_safety,
防止策略文件被直接篡改绕过 API 校验 (第3层 纵深防御)
前端: api.ts 移除 strict 参数, StrategyBuilderDialog/StrategyPoolDialog
移除 strict:true 传参 (前端本就全部传 true, 行为不变)
验证: PoC 三种攻击 payload 全部拦截, 正常策略(只import polars)无误杀
Co-authored-by: shy3130 <shy3130@users.noreply.github.com >
2026-07-14 21:32:39 +08:00
wshy and shy3130
0fba9eb57b
chore: 版本号升至 0.1.85 ( #119 )
...
Co-authored-by: shy3130 <shy3130@users.noreply.github.com >
2026-07-14 18:54:17 +08:00
wshy and shy3130
70a4aad010
feat(monitor): 个股通知带行业/概念 ext 标签 + 全局配置 ( #118 )
...
监控中心顶部加全局配置(齿轮), 选择要在个股通知里展示的 ext 字段
(默认概念 ext_gn_ths + 行业 ext_hy_ths)。开启后触发记录卡片和推送
toast 统一显示行业(蓝)/概念(橙)标签。
架构: 源头富化 — 后端 SSE 推送前 (_enrich_alerts_ext) 用
_load_ext_value_maps (带 mtime 缓存) 按 symbol 富化; GET /api/alerts
读取时同样富化。前端零额外请求。
配置支持细粒度裁剪:
- 字段下拉按扩展表分组 (optgroup)
- 显示前N个 (maxTags), 留空=全部
- 隐藏指定位置 (hiddenIndices), 点数字划掉
数据结构 {field, maxTags, hiddenIndices} 向后兼容旧字符串格式。
后端:
- preferences.py: get_monitor_ext_fields + _normalize_ext_field
- settings.py: RealtimeMonitorConfigIn + get_preferences 加字段
- quote_service.py: _enrich_alerts_ext SSE 推送前富化
- alerts.py: list_alerts 加 ext_columns 参数
前端:
- api.ts: MonitorExtFieldItem 类型 + alertsList extColumns 参数
- Monitor.tsx: 齿轮入口 + 配置弹窗 + 卡片标签行
- AlertToast.tsx: toast 底行加标签
Co-authored-by: shy3130 <shy3130@users.noreply.github.com >
2026-07-14 18:49:23 +08:00
wshy
002fb9387e
fix(docker): Codex CLI 挂载路径可覆盖 + 版本号单点维护 ( #117 )
...
PR #116 review 遗留两项非阻塞建议的后续修复:Windows 挂载路径可覆盖 + 版本号单点维护。
2026-07-14 18:16:27 +08:00
shy3130
8efc96d576
fix(docker): Codex CLI 挂载路径可覆盖 + 版本号单点维护
...
- docker-compose: ${HOME}/.codex 改为 ${CODEX_HOME_HOST:-${HOME}/.codex},
修复 Windows PowerShell/CMD 下 HOME 未设置导致挂载失败
- Dockerfile: codex-builder 阶段 ARG CODEX_CLI_VERSION 去掉重复默认值,
统一从顶层 ARG 继承(0.144.3 现仅出现一处)
- README: 补充 Windows 用户 CODEX_HOME_HOST 配置说明
2026-07-14 18:12:48 +08:00
wshy
644cf8648d
Docker 环境支持 Codex CLI ( #116 )
...
解决 Docker 容器内无法读取 codex 命令的问题:多阶段构建提取原生二进制 + 只读挂载主机登录态 + 适配 loopback local-access provider。
2026-07-14 18:07:38 +08:00
zhang,zhao
8a6c85bfc8
修复:补充 Linux Docker 主机映射
2026-07-14 17:33:55 +08:00
wshy and shy3130
d8c2081679
fix(quote): 最后获取时间持久化, 关闭开关/重启后仍显示 ( #115 )
...
_fetched_at 原为纯内存变量 (init 0.0), 进程重启即归零 → last_fetch_ms
变 null → 数据页"最后获取"显示"—"。用户关闭实时开关若伴随重启
(开发热重载/部署), 就看不到上次拉取时刻。
改为持久化到 preferences.json:
- __init__ 启动时读回 last_fetch_ms 作为 _fetched_at 初始值
- _fetch_quotes 成功后 (全市场 + 自选股两处) 写入 preferences
- 放锁外调用, 失败不影响主流程 (内存值已更新)
前端 QuoteConfigCard 本就无条件渲染该行, 无需改动。
Co-authored-by: shy3130 <shy3130@users.noreply.github.com >
2026-07-14 16:46:23 +08:00
wshy and shy3130
d99112c160
分时图实时刷新: 日期修复 + 间隔可配 + 对话框实时 + 自选刷新图标 ( #114 )
...
* fix(kline): 分时图盘中显示昨天而非今天
get_minute_batch 的日期选择存在死循环: trade_date=date.today() 后立即
if trade_date==date.today() (恒真), 无条件用 latest_minute_date_global()
覆盖今天; 但批量实时补拉不落库, 该值盘中恒返回昨天 -> 永远回退到昨天 ->
expected=240 判定昨日完整 -> 不触发今天补拉。
改为仅在真正非交易日回退 (周末 + 收盘后无今日日K 的节假日), 盘中保持
今天让 completeness 检查触发实时补拉。同时全量 date.today()/datetime.now()
改用北京时间 cn_today()/cn_now(), 与 quote_service/monitor 等一致。
影响: 自选列表分时列 + 单股详情分时图。
* feat(settings): 分时图刷新间隔可配置 (默认6s, 范围3-60s)
原写死 15s 轮询, 现可在 实时监控设置 -> 分时图刷新 卡片用滑块调节。
复用 minute_intraday_refresh 偏好链路, 新增 minute_intraday_refresh_interval
字段 (preferences + settings API + 前端 Preferences 接口)。
- preferences.py: getter 默认6s clamp[3,60] + set/get config 接入
- settings.py: RealtimeMonitorConfigIn 字段 + get_preferences 返回
- Monitoring.tsx: 滑块控件 (参考行情轮询滑块, 2s 防抖保存)
- Watchlist/Screener: 15_000 -> interval*1000, fallback ?? 6
* feat(dialog): 个股对话框日K/分时实时刷新
日K走 SSE 精准刷新: 对话框打开时注册焦点股票, quotes_updated 推送时
invalidate ['kline', symbol], 后端 _maybe_inject_live_candle 只读内存
不调 TickFlow, 秒级零成本。关闭/切股自动注销焦点。
分时走轮询: 复用分时刷新开关 + 间隔偏好, 经 StockPanel.refetchIntervalMs
透传到 StockIntradayChart。分时端点数据不完整会调 TickFlow, 不接 SSE
避免打爆限流。
不影响回测弹窗 (不注册焦点、不传间隔)。
* feat(watchlist): 分时列表头加刷新图标 (与策略列表一致)
分时列可见 + 未自动刷新时显示手动刷新按钮 (点击 refetch, 加载旋转);
自动刷新中显示持续旋转小图标提示。逻辑/样式对齐 ScreenerTable。
* fix(badge): 真假涨停修正弹层被父级裁剪遮挡
弹出层原用 absolute 定位, 被看板卡片父级的 overflow-hidden +
backdrop-blur containing block 裁剪/遮挡。改用 createPortal 渲染到 body,
基于徽章 getBoundingClientRect 计算弹层坐标, 脱离父级裁剪。
---------
Co-authored-by: shy3130 <shy3130@users.noreply.github.com >
2026-07-14 15:46:18 +08:00
zhang,zhao
46338f4435
修复:适配 Docker Codex 本地访问服务
2026-07-14 11:51:35 +08:00
zhang,zhao
452816aee3
文档:补充 Docker Codex CLI 使用说明
2026-07-14 11:51:35 +08:00
zhang,zhao
8206a6010d
修复:Docker 模式支持 Codex CLI
2026-07-14 11:51:35 +08:00
zhang,zhao
79bdaf3818
文档:设计 Docker 模式 Codex CLI 支持
2026-07-14 11:51:35 +08:00
wshy
77c0c643b2
Update README.md
2026-07-14 11:21:16 +08:00
wshy
5a483501e8
Merge pull request #113 from shy3130/fix/intraday-refresh-and-voice-pct
...
fix: 分时刷新开关不生效 + Pro+默认开启 + 语音涨跌幅漏乘100
2026-07-13 22:29:13 +08:00
shy3130
4df5cc3b27
fix(voice): 涨跌幅播报漏乘 100, 几乎所有股票都念成「涨0.0%」
...
fmtPctText 直接 pct.toFixed(1), 但后端 change_pct 是小数制
(0.0366 = 3.66%, 见 quote_service.py「不乘 100」注释)。屏幕显示的
fmtPct (format.ts) 正确 ×100, 但语音的 fmtPctText 单独写漏了。
0.0366 → 旧「涨0.0%」/ 新「涨3.7%」
0.10 → 旧「涨0.1%」/ 新「涨10.0%」
×100 后再 toFixed, 与 fmtPct 单位约定一致。tsc 通过。
2026-07-13 22:28:16 +08:00
shy3130
590de5d694
fix(monitor): 分时图刷新开关不生效 + Pro+ 默认开启 + 刷新条件统一
...
三处问题:
1. 后端 API 漏接线 (settings.py):
- 入参模型 RealtimeMonitorConfigIn 缺 minute_intraday_refresh →
PUT 时 Pydantic 静默丢弃, 开关拨了也不存
- GET /preferences 响应没返回该字段 → 前端永远读 undefined→false,
开关拨完弹回 OFF
服务层 (preferences.py) 本就有 get/set, 纯 API 层漏接。
2. 默认值 (preferences.py):
get_minute_intraday_refresh 原默认 False。改为三态: 未设置过的
key 按 Pro+ 权限定默认 (有权限=开, 无=关); 用户主动设置过的
(含 False) 以用户选择为准。用 'in data' 区分 未设置 vs 设为 False。
3. 刷新条件不一致 (Watchlist.tsx):
Watchlist 用 || (开关或实时行情任一即刷新), Screener 用 && (两者都要)。
与设置卡片描述「需 Pro+ 权限 + 实时行情运行」对齐, 统一成 &&。
后端 216 测试通过; 前端 tsc 通过。
2026-07-13 22:28:04 +08:00
wshy
933d216c83
Merge pull request #111 from shy3130/fix/dev-ps1-utf8
...
fix(dev): dev.ps1 Start-Job 子进程强制 UTF-8, 修后端中文日志乱码
2026-07-13 20:51:59 +08:00
shy3130
40c197149e
fix(dev): dev.ps1 Start-Job 子进程强制 UTF-8, 修后端中文日志乱码
...
Start-Job 开的是全新 powershell.exe 子进程, 不继承主进程第 25-28 行
设的 UTF-8, 默认用系统 ANSI (中文 Windows = GBK/cp936) 解码后端的
UTF-8 输出 → 中文变 '瀹氫箟缂哄皯' 式乱码 (UTF-8 被当 GBK 解)。
第 25 行注释 'so child process logs aren't garbled' 的意图因 Start-Job
开新进程而落空。在 backend/frontend 两个 scriptBlock 开头各设 UTF-8,
与 app/__init__.py 的 stdout/stderr 编码对齐。
PowerShell 语法校验通过。
2026-07-13 20:51:23 +08:00
wshy
a0fec8a754
Merge pull request #110 from shy3130/fix/wf-nan-rendering
...
fix(walkforward): 汇总数值 NaN/Infinity 渲染兜底
2026-07-13 18:54:46 +08:00
shy3130
95c918c841
fix(walkforward): 汇总数值 NaN/Infinity 渲染兜底
...
#104 审查发现 StrategyWalkForward 的汇总卡和净值曲线在后端返回
NaN/Infinity (零成交折等边界) 时会渲染出 "NaN" 字样或空白 SVG:
- OosEquityChart: vals 含 NaN → lo/hi/span 全 NaN → SVG 路径空白,
页脚 last.toFixed(4) 显示 "NaN"
- IS→OOS 退化 / 目标均值: degradation != null 对 NaN 为 true,
toFixed(3) 显示 "NaN"; 颜色判断 (NaN > 0 = false) 方向也错
修复: 加 fin() 把非有限值归一为 null, JSX 外用 const 取出归一值
(TS 据此收窄类型), 下游统一走 '—' 降级。复利收益/一致性/OOS 收益
本就走 NaN-safe 的 fmtPct, 无需改。
前端 tsc -b + vite build 通过。后端未改动。
2026-07-13 18:54:13 +08:00
wshy
79b86b26a0
Merge pull request #105 from im47cn/fix/task-reconnect-cleanup
...
fix(optimizer): SSE 放弃时清 localStorage + JSON 解析失败告警
2026-07-13 18:49:24 +08:00
wshy
b869f3a552
Merge pull request #104 from im47cn/feat/wf-optimization
...
feat(walkforward): 滚动窗口 walk-forward 优化 — IS 优化 + OOS 验证
2026-07-13 18:48:47 +08:00
wshy
31596824d7
Merge pull request #109 from shy3130/fix/ext-concepts-cast-and-meta-normalize
...
fix: 扩展数据 List cast 报错 + AI 策略 META 规范化失败
2026-07-13 18:40:49 +08:00
shy3130
7062dcd94d
fix(strategy): AI 生成 META: dict = {...} 时规范化报错「找不到 META 字典」
...
LLM 常给 META 加类型注解 (ast.AnnAssign 节点), 旧版 _find_meta_dict
只遍历 ast.Assign 漏掉注解形式 → 抛「找不到 META 字典」→ 上层包成
「规范化 META 失败」。校验 (_extract_meta) 与规范化 (_find_meta_dict)
用两套不一致逻辑, 导致「校验通过、规范化失败」。
两个函数统一增加 ast.AnnAssign 分支, 消除不一致。补充 4 个回归测试
覆盖注解形式 (含端到端 _normalize_build_result 路径)。
修复后无论哪台机器、哪个模型生成都不再触发该错误。
2026-07-13 18:39:17 +08:00
shy3130
570bcba8b9
fix(ext-data): List→string 字段直接 cast 报错 — 先 join 再 cast
...
手动创建的扩展配置拉取 THS 概念接口时, concepts 列为 List(String),
声明为 string 后 cast_df_to_schema 直接 cast(pl.Utf8) 抛
「cannot cast List type (inner: String, to: String)」。
cast_df_to_schema 检测到源列是 List 且目标为 Utf8 时, 先把元素
转字符串再以分号拼接 (与 _flatten_concept_rows 一致), 然后再 cast。
保护任意返回数组字段的配置, 不再依赖预设 id 走 flatten 分支。
2026-07-13 18:39:10 +08:00
shy3130
ede22336fa
docs: clarify Docker deployment behavior
2026-07-13 00:05:07 +08:00
wshy and shy3130
697ff2a181
fix(compliance): reinforce research-only boundaries ( #108 )
...
Co-authored-by: shy3130 <shy3130@users.noreply.github.com >
2026-07-12 22:42:38 +08:00
im47cn
b4fa9d6eb4
fix(optimizer): SSE 放弃时清 localStorage + JSON 解析失败告警
...
对抗式审查发现的两处健壮性问题 (与 walk-forward 同源, 此为优化器侧):
- stopOptimize 延迟分支 + MAX_RECONNECT 超限退出漏清 localStorage, 导致刷新页面
tryReconnect 会重连到已放弃/未取消的任务。两处补 removeItem(RECONNECT_KEY/JOB_KEY_KEY)。
- optimize_stream 的 params/overrides JSON 解析失败静默降级为 {}/None, 会让用户配置
丢失变成无声 bug。升级为 logger.warning (仍降级不崩流, 但可诊断)。
2026-07-12 22:22:36 +08:00
im47cn
5ea58f6a8d
fix(walkforward): SSE 放弃时清 localStorage + JSON 解析失败告警
...
跨组件后续修复的 WF 侧 (优化器侧同款问题另起 PR):
- stopWalkForward 延迟分支 + MAX_RECONNECT 超限退出漏清 localStorage, 导致刷新页面
tryReconnect 会重连到已放弃/未取消的任务。两处补 removeItem(RECONNECT_KEY/JOB_KEY_KEY)。
- walkforward_stream 的 params/overrides JSON 解析失败静默降级为 {}/None, 会让用户配置
丢失变成无声 bug。升级为 logger.warning (仍降级不崩流, 但可诊断)。
2026-07-12 22:18:11 +08:00
im47cn
e4262d9951
fix(walkforward): IS 训练折强制 position 模式, 堵前视泄漏
...
对抗式审查发现: WF UI 暴露 full 模式, 选中时训练折(end=train_end)未平仓的持仓
会用 train_end 之后(即 OOS 区间)的真实 K 线平仓 -> IS 分数被未来数据污染, 优化选出
的最优参数乐观偏移, 使过拟合被掩盖 (对专门检测过拟合的 WF 工具危害尤重)。
修复: IS 训练区间优化强制 mode="position" (只看正式区间表现), OOS 回测保留用户
所选 mode。新增测试: 用户选 full 时断言每折 IS 得到 position、OOS 保留 full。
2026-07-12 21:48:13 +08:00
shy3130
97e1cdcc78
feat(backtest): 交易记录显示具体触发信号 (不再只显示「信号」类别)
...
原问题: 多个信号在 _build_signal_mask 里 OR 成一个 mask 后, 只记录
exit_reason="信号", 具体哪个信号触发的信息丢失。回测里买入/卖出原因
只能看到笼统的「信号」, 不知道是 MA金叉还是 MACD死叉。
实现:
- 后端 TradeRecord 加 entry_signal_id/exit_signal_id 字段
- 新增 _resolve_signal_id() 在触发行回查 panel 列, 找出为 True 的具体信号
- 三个 simulate 方法加 entry_signal_ids/exit_signal_ids 参数
- strategy.py 把信号列表传给 engine, _trade_to_dict 透传新字段
- 前端 useSignalNames() hook 合并内置 (BUILTIN_SIGNAL_DEFINITIONS) + 自定义
信号名称; TradeLegCell/ExitReasonBadge 显示具体信号名
- 信号名称前端解析 (复用 cnSignal), 后端只返回 signal_id, 不读磁盘
效果: 买入腿显示「MA5上穿MA20」, 卖出腿显示「MACD死叉」, 原因列从
通用「信号」变成具体信号名。止损/止盈/到期等非信号退出不受影响。
验证: 191 passed, 前端类型检查无错误
2026-07-12 18:31:36 +08:00
shy3130
ff059a0cda
fix(backtest): 分钟K回测爆内存 — 按触发日精确读取 + 紧凑数组缓存
...
上一提交 (365f1cc ) 修 index bug 时把 cache 从紧凑 numpy 数组改成臃肿的
polars DataFrame, 分钟K回测内存翻几倍导致 OOM 死机。且 _load_minute_for_fills
用 get_minute_range 扫描整个触发区间 (start~end), 触发日稀疏时读了大量无关
日期, 全市场长周期回测直接爆内存。
修复:
1. repository 新增 get_minute_by_dates — 按日期列表精确读 date=YYYY-MM-DD
分区文件, 不扫描区间。内存与回测区间长度解耦, 只随触发日数量增长。
2. _load_minute_for_fills 改用 get_minute_by_dates, 每批 50 天分批读取。
3. cache 改回 float64 紧凑 2D 数组 (6 列: open/high/low/close/volume/amount),
.cast(Float64) 保证 to_numpy 不退化回 object, 原来的 index bug 不复发。
4. _resolve_minute_fill 改用整数列索引 (arr[:,0]) 替代列名索引。
内存对比 (全市场 1 年):
之前: get_minute_range 扫全年 ~365 文件 + DataFrame 缓存 → 5-10GB
现在: 只读触发日文件 + float64 数组 → 几十 MB
验证: 191 passed (含 7 个分钟K回归测试)
2026-07-12 18:01:19 +08:00
shy3130
365f1ccbfb
feat(minute-k): 分钟K同步流式落盘 + 段大小可配 + 回测成交修复 + 卡死超时调整
...
1. 分钟K流式落盘 (修复1年全市场卡死)
- sync_minute_batch 加 on_segment 回调,每段拉完立即写盘
- 抽出 _write_minute_partition 公共函数,消除重复
- 内存峰值从全量(~25GB)降到单段,避免 OOM
2. 段大小可配 (默认20交易日,范围[5,30])
- 新增 minute_sync_segment_days 偏好项
- 「单次获取」与「获取1年」共用此分段设置
- 前端设置弹窗新增分段大小步进器
3. 回测分钟K精确成交修复 (从未成功跑通过)
- _resolve_minute_fill 改接受 DataFrame,避免 to_numpy() 退化为
object 数组后字段名索引抛 IndexError
- _load_minute_for_fills 用 partition_by 向量化分组替换逐行循环
- 新增 test_minute_fill.py 回归测试 (6 用例)
4. 卡死 watchdog 超时阈值按任务类型区分
- 普通任务 600s → 1200s;分钟K长任务 → 1800s
- create(timeout_s=) 支持按 job 存阈值,reap_stale 读 job 自身值
- 修复分钟K正常拉取被误杀导致僵尸线程继续写盘的问题
5. UI 优化
- 设置弹窗按 自动同步/手动获取/清空 三区块分组
- 「单次获取」改为按分段大小拉一段 (天数=分段设置)
- 状态文案: 盘后自动同步 → 自动同步已开启/已关闭
2026-07-12 14:23:22 +08:00
im47cn
8d93b8fe98
fix(walkforward): 前端对齐优化器已有防护 (切策略停任务 + 坏网格拦截)
...
对抗式审查发现 WF 页面偏离了 StrategyOptimizer 已修好的两处防护:
- 切策略时直接传 clearWalkForward (只清前端状态), 不停后端任务 —— 对齐优化器
改为 if(pending) stopWalkForward() else clearWalkForward(), 真正 cancel+关SSE+清storage。
- canRun 缺 !sweep.gridError, 且 CombosHint 未传 gridError prop —— 坏网格(步长越界等)
既不显示错误也能提交到后端。补齐, 与优化器一致。
2026-07-12 14:10:15 +08:00