Commit Graph
29 Commits
Author SHA1 Message Date
awayingsandClaude Code fb35677802 feat: 自选列表新增「近3日/近1周/近2周」涨跌幅三列(issue #7)
交易日偏移口径:T = 上证指数日线(交易日历)中 <= 今天的最后一天,
D_n = T 往前 n 个交易日,锚点 = 个股日线(/bars 同款 QFQ)中
date <= D_n 的最后一根 bar。后端只回锚点收盘价,涨跌幅由前端用
SSE 实时价现算,盘中三列随报价免费跳动、无需轮询本接口。

- 新增 GET /watchlist/returns + 纯计算模块 web/returns.py(零 IO,单测覆盖
  停牌回退/次新 null/除权日 QFQ/非交易日回退等口径)
- 个股日线与交易日历均进程内缓存(当日不变、次日失效),重复刷新零行情请求;
  日历缺今天(serve 盘前启动)时按 60s 间隔重取,避免 T 整体前移
- 取数并发 ≤ 4(TDX 防封红线);单只失败只落 error,不影响整表
- 前端 +3 列(着色复用 dirClass/fmtPctSigned),e2e 同步断言

与 issue 定稿的两处偏差(/simplify 收敛,"减少不必要的改动"):
- 删除 windows 查询参数:列名与窗口一一对应(issue 亦将"用户自定义窗口"
  列为 out of scope),固定 3/5/10
- 个股缓存由磁盘 JSON 改为进程内 dict:可观测行为不变(当日不重复请求),
  但 serve 重启后当天首次请求会重取一次

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-11 11:39:10 +08:00
Justin Gu e374a0da28 release: v1.32.6 — 两周改动深度审查全面修复(回测口径三件套/LLM 安全加固/涨停价舍入/时区统一/缓存与竞态等 58 处)
对 v1.21→v1.32.5 的 249 文件 4.2 万行改动做六路专项审查,本轮落地全部发现:

回测正确性:组合收益 fillna(0) 虚增、轮动停牌日过期价成交、单标的 WF 逐窗指标
被预热区稀释(三件套均带先红后绿回归);worst_drawdown 方向、grading 容错、
组合体检品种费率、寻优端点费率透传。

安全:LLM api_url 仅 http/https 且禁 userinfo(封死 file:// 读取与 Key 外送链)、
错误响应不回显原始 body、响应体 2MB 上限、配置原子写、坏配置字段级防御。

数据:涨跌停价整数分币舍入(67/318/90 个价位错 1 分漏判清零)、交易时段/采样/
provisional 统一沪时区、warehouse 增量缺口自动全量重拉、provisional 定点转正、
baostock 真故障抛错 + W/M 去 tradestatus(实测服务端报错,周月兜底此前从未工作)
+ 指数 vol 股→手(实测锚定)、ccpm 结构变更抛错。

Web API:缓存键补 count/vipdoc、NaN 清洗先于缓存、count>800 分页取全量、
submit 透传真实状态、pending 不再被淘汰成幽灵、watchlist/server 入参约束。

公式:FILTER 去副作用、0-1 值域误判收严、递归深度上限、REF 负移位显式禁止。

前端:4 处请求竞态序号守卫、Sparkline viewBox、北交所 market=2 映射、
空数据缓存死角、AI 弹窗卸载中止轮询、量能/资金日历口径修正。

CLI/CI:warehouse sync 失败 exit 1、参数校验干净报错、release 真实发布 SHA256、
CI 超时与缓存、spec 补 baostock 前提。

约 60 条回归测试先红后绿;pytest 1820 全过,ruff/mypy/vue-tsc/node --test 全绿。
2026-09-06 22:16:48 +08:00
Justin Gu d5cf9c14a9 feat(web): 品牌区显示应用版本号 — 新增 GET /api/v1/meta,前端启动拉取展示 2026-09-06 14:34:59 +08:00
Justin Gu aead122478 feat: 涨停生态 vipdoc 路径可配置 — 应用级 KV 设置 + 页面配置行
- 新增 AppSettingsStore(~/.easy_tdx/settings.db,KV 持久化,重启不丢)
- GET/PUT /settings/vipdoc:读取/保存本地 vipdoc 目录(保存即校验目录
  存在,并清空涨停生态/历史缓存,下次扫描立用新路径;空串=恢复自动检测)
- vipdoc 解析优先级:显式参数 > 已存设置 > 自动检测(TDX_HOME/常见路径)
- /limitup-ecology 响应携带 vipdoc_path 供页面展示生效目录
- 涨停生态页头部新增路径配置行(输入框+保存+恢复自动检测),
  未检测到数据的空态文案引导填写
2026-09-05 11:24:48 +08:00
Justin Gu 7f0f14532e refactor: 移除异动雷达 — 数据源盘中几乎无记录,功能不达预期
- 删除 /radar 页面与导航、看板「异动雷达」卡片、fetchUnusual 封装
- 移除 /mac/unusual HTTP 端点(MAC 协议层 get_unusual 与 mock 保留,
  属协议覆盖面);路线图 ③ 标记取消
2026-09-05 04:42:53 +08:00
Justin Gu 0a205ffbf3 feat: 盘面洞察第四批 — 板块相关性热力图 + 异动雷达 + 量能仪表盘
- 相关性 /hotspots 页内新增「相关性」视图:/board-mac/hotspot-correlation
  复用热点历史矩阵缓存,对窗口内活跃板块(每日前 per_day 名并集,按上榜次数
  取前 N)两两算日涨跌幅 Pearson 相关;红=同涨同跌(抱团)、绿=跷跷板(轮动),
  ECharts 热力图 + 双向色阶 visualMap;无缓存时透传 building 状态
- 异动雷达 /radar:沪深异动流时间线(封板/炸板/大笔买入/逼近涨停…),
  每分钟异动密度柱 + 类型筛选 chips(带计数),行点击直达个股弹窗,15s 轮询
- 量能仪表盘并入市场情绪页:两市(上证+深成 5 分钟线)累计成交额曲线
  vs 近 5 日同期均值(虚线),标题给出偏离百分比——放量/缩量一眼可辨
- 热点缓存判定重构为 _hotspot_history_or_build 公共入口,correlation 与
  hotspot 共用同一构建状态机;新增相关性矩阵回归单测
2026-09-05 04:09:03 +08:00
Justin Gu 37c732fb30 fix: 板块弹窗成分股写死 120 只截断 — 改全量拉取
BoardDialog loadMembers 硬编码 count=120,CPO(205 只)、半导体(185 只)
等大板块的成分股榜永远少一大截。改为 1000(后端单页 80 自动翻页,
拉满后按成员清单自然终止,典型 200 只板块仅 3 个请求);
fetchBoardMembers 缺省值同步对齐。

注:688801 燧原科技 MAC 报价缺前收(pre_close=0),前端已有除零守卫,
属数据源口径而非排序问题。
2026-09-05 03:41:03 +08:00
Justin Gu 2b86a7d588 feat: 市场情绪栏目 — 盘中情绪采样器 + 宽度分时 + 涨停史离线回补
- /sentiment 市场情绪:温度卡(实时上涨占比/涨跌停/总成交,五档情绪判定)
  + 今日宽度分时(上涨/下跌/涨停家数三线)+ 近 60 日涨停跌停家数与上涨占比
- SentimentSampler:交易时段每分钟采样全市场广度(get_market_stat),
  停牌/盘外自动跳过、失败不中断;SentimentStore 落 SQLite
  (~/.easy_tdx/sentiment.db,(date,minute) 幂等主键,重启不丢)
- /market/sentiment/today|history:当日分钟曲线 + 逐日聚合(收盘快照占比/峰值)
- /market/limitup-history:涨停跌停家数逐日历史由 vipdoc 离线回补,
  无需采样积累即时可用;缓存按 days 分键(修复 10 天缓存被 60 天请求命中)
- 采样历史需交易日积累,页面空态有明示;涨停/跌停历史开箱即有 60 天
2026-09-05 03:10:19 +08:00
Justin Gu e419f911b7 feat: 盘面洞察三栏目 — 热点滚动/大盘日历/涨停生态,移除龙头池
- 热点滚动 /hotspots:交易日×板块涨跌矩阵(行业/概念/风格FG、领涨领跌镜像、今日~30日窗口),
  每日名次徽标+连板/累计/首榜统计,统计卡可点击展开成员板块;后端 /board-mac/hotspot
  两段式数据(历史日K矩阵当日缓存 + 今日实时列,周末 pre_close 未滚动去重),
  单连接约束下后台构建+进度轮询;风格轮动 /styles 为同视图 FG 路由别名
- 大盘日历 /calendar:指数全年红绿热力图,方框大小编码成交额(年内四分位),
  悬停浮框显示收盘/涨跌幅/成交额
- 涨停生态 /limitup:本地 vipdoc 日线离线回算连板天梯/首板二板分布/炸板率/跌停;
  仅统计最后一根 bar 等于全市场最新交易日的股票(防停牌/退市/未下载陈旧文件污染),
  主板 5% ST 判定带低价护栏;名称前端经 symbol-info 懒加载补齐
- 移除龙头池栏目及 /market/core-leaders 端点(screen 模块 universe=core 保留)
- 设计文档:docs/hotspot-rolling-design.md、docs/market-insights-roadmap.md
2026-09-05 02:43:02 +08:00
GitHub f6560f3c6d feat: 行业/概念总览 — WebUI 板块总览双栏目(统计条+热力图/表格+三榜/翻红翻绿+板块弹窗复用)+ /board-mac/overview 聚合端点(多排序归并+15s缓存) 2026-09-04 15:59:57 +08:00
GitHub 497ac21e5a fix: 策略库「重跑到今天」补齐组合分析 — 多策略组合级WF/一条龙/AI解读
策略库(/strategies)多策略组合卡片此前只有主回测:本轮把 v1.31.0
的组合分析链路延伸到多策略组合(N 策略 × 各自原标的):

- walkforward:组合 WF 泛化为槽位模型(_ComboSlot/_ComboWalkForwardBase),
  PortfolioWalkForwardEngine 行为不变;新增 MultiStrategyWalkForwardEngine
  (N 个策略各跑各自原标的,key 形如 label@symbol),复用切窗语义与
  WalkForwardResult 结构(前端 WalkForwardPanel 直接渲染)
- benchmark:新增 evaluate_multi 一条龙(MultiStrategyEngine 回测 + 多策略
  组合 WF + 逐槽位三段体检多数口径聚合 + 综合评分 + 组合评级 + 各槽位标的
  等权买入持有基准对比),报告结构与单标的 evaluate_strategy 同构
- Web:新增 POST /backtest/multi-strategy/wf/run/async 与
  /backtest/multi-strategy/evaluate/run/async;多策略组合回测响应附带
  grade/score(与单标的/多标的组合响应同构)
- 前端 StrategiesView:组合结果区新增「WF 样本外验证 / 一条龙评估 / AI 解读」
  按钮与同构面板(按需触发,复用最近一次组合回测的 items/cash);
  绩效指标表补齐 v1.28 深度 6 项(SQN/最大连胜连亏/Ulcer/VaR/CVaR);
  aiPrompt 新增 multi 模式(策略明细语境 + 槽位表现段)
- 测试:多策略 WF 引擎 3 例、evaluate_multi 3 例、新端点 Web 级 2 例、
  aiPrompt multi 模式 1 例(pytest 1611 绿、node --test 5/5、E2E 9/9)
2026-09-03 23:54:29 +08:00
GitHub c49ba4c4b5 feat: 组合回测分析体系对齐单标的 — 组合级WF/一条龙/完整25项绩效/AI解读
组合回测(一策略×多标的)此前只能看 4 个数字,本轮把单标的的整条
分析链路在组合端补齐(WebUI/REST 双端):

- portfolio_engine:合并净值+汇总成交喂 PerformanceAnalyzer,输出
  完整 25 项指标(SQN/最大连胜连亏/Ulcer/VaR/CVaR 等)+ 组合层
  trades(symbol 列);修复假年化与回撤口径(负值+固定分母 →
  逐点峰值,与单标的/多策略一致)
- walkforward:新增 PortfolioWalkForwardEngine,按标的日期并集切窗、
  每窗独立开仓、合成组合窗内净值,复用 WalkForwardResult 结构
- benchmark:新增 evaluate_portfolio 一条龙(组合回测+组合WF+
  跨标的多数口径适配性体检+综合评分+组合评级+等权买入持有基准对比),
  报告结构与单标的 evaluate_strategy 同构
- performance:FIFO 持仓天数配对支持 symbol 分组
- Web:新增 POST /backtest/portfolio/wf/run/async 与
  /backtest/portfolio/evaluate/run/async;组合回测响应附带
  grade(组合净值口径)与 score;新增 _normalize_bars_dt 修复
  按标的取数路径的字符串日期/遗留 date 列崩溃(E2E 揭露)
- 前端:组合页新增附加分析勾选区与组合绩效指标/WF/一条龙/成交明细
  区块;buildPortfolioAiPrompt 组合版 Prompt;抽通用
  AiInterpretModal(回测页迁移共用,行为不变);TradeTable 支持
  showSymbol;EvaluatePanel 支持 gradeOverride
- 测试:后端 +17 例(pytest 1603 绿)、aiPrompt 组合版 2 例、
  Playwright 组合页 E2E 2 例(9/9 绿)
2026-09-03 23:22:48 +08:00
GitHub 99397a12e3 feat(ccpm): 中金所成交持仓排名采集——CLI/API/WebUI 三端 + 新手科普
- 新增 easy_tdx.ccpm 模块(独立数据源,标准库 urllib 零依赖):
  官网 /sj/ccpm/{YYYYMM}/{DD}/{品种}.xml,交易日约 16:15 发布,
  单文件含全部合约 × 三类排名(datatypeid 0=成交量/1=持买单/2=持卖单)× 前 20 名会员
- 协议要点:?id= 为 0~99 随机防缓存参数可省略;非交易日 302→error_404,
  禁用 urllib 自动重定向并翻译为 CcpmNoDataError(区别于网络错误 CcpmError);
  仅 http 可用;历史可回溯至 2012 年
- 8 品种:IF/IH/IC/IM 股指 + TS/TF/T/TL 国债;latest_rank() 自动回溯最近交易日;
  按日不可变 → ~/.easy_tdx/cache/ccpm/ 落盘缓存,历史二次查询零网络
- CLI:easy-tdx ccpm IF [--date] [--table] [--refresh] [--no-cache],all=全品种
- API:GET /ccpm/products(品种科普元数据)+ GET /ccpm/rank?product&date
  (404=非交易日/未发布,refresh 强制重抓)
- WebUI「期货持仓排名」页(行情组):品种下拉+日期+自动回溯开关+一键采集,
  合约页签自动标注主力,前 20 合计多/空/净持仓概览,三组排名并排表格
- 三段新手科普:「这是什么数据」「品种一览」「多单空单加减仓怎么看」
  (强调排名看不出套保还是投机,空单多 ≠ 看空市场)
- 测试 20 例(mock HTTP 零网络):解析/缓存/302 语义/回溯/路由/CLI
2026-09-02 20:54:59 +08:00
GitHub 4bd5b5d833 release: v1.29.0 — 借鉴社区 Fork 六项特性:ZIG 策略 + 交易时段感知刷新 + 120M K 线 + 逐 bar 衍生字段 + 159 龙头池 + 多 Provider LLM 直连
- ZIG 右侧突破回补策略:MyTT 新增 ZIG 之字转向(未来函数,含前视偏差警示);
  波谷启动建仓挂硬止损(OCO)→ 见顶清仓记前高 → 右侧突破回补;路径依赖不实现
  entry_exit_masks(向量化守护测试白名单);含寻优预设网格与 --strategy-file 独立文件
- 交易时段感知刷新:realtime/session.py(09:15~11:30:30 / 13:00~15:05)+
  GET /market/session;看板 30/60/120s 轮询休市自动暂停(三态状态栏 + 开关持久化
  + 手动刷新不受限);SSE/WS 既有会话语义不动
- 120 分钟 K 线:/bars?category=MIN_120(MAC 原生 Period.MINS×120 优先,
  2×60M 相邻聚合兜底,标准客户端上限 400 根);前端周期选择器同步
- 逐 bar 衍生字段:/bars 与 /bars/index 附带 pre_close/change/change_pct/
  amplitude_pct(pre_close≤0.01 兜底防除零)
- 159 只核心龙头池:数据资产取自 Fork(东财全行业龙头名单,四组分层);
  universe=core 接入 screen scan / SignalScanner / StrengthRanker / market strength;
  GET /market/core-leaders + WebUI「龙头池」页(搜索/个股详情)
- 多 Provider LLM 直连:easy_tdx.ai + /llm/*(DeepSeek/通义/智谱/Kimi/MiniMax/
  OpenAI/Claude/Ollama/自定义,openai 兼容 + anthropic 原生双协议);
  配置落盘 ~/.easy_tdx/llm.json(WebUI「AI 设置」页 ⇆ 手工编辑双向兼容,
  文件>环境变量>预设;key 脱敏回显/CLEAR 清除);「AI 解读」后台任务化
  (复用 task_runner,提交+轮询,不占 HTTP 连接);思考型模型空白正文防御
  (reasoning_content 耗尽 max_tokens → 可操作报错;默认 16000);
  AI 解读历史页(自动归档 Prompt/正文/策略上下文 + 去回测带参引导)
- WebUI 加固:SPA fallback 对未知 /api/* 返回 JSON 404(不再 200 HTML 伪装解析错);
  index.html 一律 Cache-Control: no-store(防缓存旧资源引用);路由兜底重定向;
  全局风险提示常驻底栏 + 龙头池/AI 解读针对性免责声明
- 测试:新增 9 个单测文件共 59 例;黄金基线仅新增 zig_breakout 条目(其余零漂移);
  全量 1448 例通过
2026-09-02 20:19:17 +08:00
GitHub 917295edaf release: v1.27.0 — 通达信公式解析器三通道 + 轮动组合引擎 + 回测页WF/评估开关 + Docker 部署
升级计划 P3 + P4(部分)。全量 1252 单测、ruff/mypy strict、前端 vue-tsc+vite build 全绿。

- 通达信公式解析器(formula.py):自建 tokenizer + 递归下降 AST + 30+ 函数白名单求值
  (不走 Python eval);命名布尔输出=信号列、数值输出=排名列;除零→NaN、预热期不出信号
- 公式三通道:CLI easy-tdx formula compute|screen|backtest;REST /formula/validate|compute|
  backtest|screen(run/async);Python API run_formula_backtest(买/卖列自动挑选)
- 轮动组合引擎(rotation.py):排名定期换仓(打分只用截至当日数据)、槽位等额、
  跌出排名自动补位、日/周/月刷新、槽内止盈止损;momentum_score/formula_score 打分;
  REST /backtest/rotation/run/async
- 回测页附加分析开关(Web UI):勾选后随回测并行跑 WF(逐窗红涨绿跌柱状图+汇总卡,
  窗口数 2~12)与一条龙评估(评分分项条/高适配徽标/买入持有对比/8 项适配检查);
  新增 WalkForwardPanel/EvaluatePanel 组件与 store runWalkforward/runEvaluate;
  WF 端点 ?n_windows= 透传;修复报告 numpy 标量 REST 400(源头清洗)
- Docker 部署(Dockerfile + docker-compose.yml,/data 卷 + 健康检查)与
  scripts/verify_ci.sh 一键门禁
- 升级计划文档 docs/upgrade-plan-2026H2.md(四阶段全部完成 + 诚实实测数据)
- 未做(独立排期):Playwright E2E、WebSocket 实时联动、引擎逐 bar 向量化
2026-09-01 22:17:57 +08:00
GitHub 33d44ba5d6 feat(webui)!: 行情终端重大升级——市场看板/自选/个股与板块弹窗 + SSE 实时推送
展示层对标专业看盘终端(tick-stock-panel 模式),数据全部来自通达信协议直连:

- 市场看板:五大指数实时条(迷你分时)、涨跌统计、四维情绪雷达、
  全市场涨跌分布直方图(约 5500 只 22 桶、鼠标跟随浮窗)、涨停雷达、
  行业/概念热冷榜(可下钻)、涨幅/跌幅/成交额/换手四联排行榜、异动雷达
- 自选行情:6 位代码即加(symbol-info 自动取名)、SSE 实时全表刷新、
  行内迷你分时;SQLite 持久化(watchlist.db,幂等加删)
- 个股弹窗:五档盘口 + 1/3/5 日分时 + 日K(MA/BOLL/EMA + MACD/KDJ/RSI
  前端本地计算)+ 一键加自选 + 一键全策略寻优
- 板块弹窗:板块分时/日K + 成分股涨跌榜直达个股
- SSE 架构:QuoteStreamer 单循环轮询 fan-out(独立队列 + 背压丢旧、
  无订阅休眠、盘中 8s/盘外 60s 降频);前端 pinia 单连接指数退避重连
- fix(codec): SH 000 系大盘指数与 881/885 板块指数报价按 2 位小数解析
  (曾缩小 10 倍:科创50 1647.53→164.753);880 统计指数保持 3 位
- fix: 前端批量五档路径 /security/quotes→/quotes、SSE 五档白名单
  bid1_vol→bid_vol1、MAC 排行 close 列归一化、日K v-if 撑满、
  寻优查看跳转 /→/backtest、FastAPI 0.141 _IncludedRouter 测试适配

新增 27 个单测(streamer/自选/小数位语义),全套 1078 passed
2026-09-01 17:45:07 +08:00
GitHub 9336273f17 feat(web): 信号雷达——一键扫描全部已保存策略的最近买卖信号
新增导航页 /signals:把策略库 single/portfolio/multi 策略统一展开成
"策略×标的"子任务,按标的去重取最近 800 根 K 线,用与回测引擎同口径的
逐 bar 信号流程(含仓位跟踪)判断最近 N 根(窗口 1/3/5/10 可选,默认 5)
的买/卖信号,汇总卡片 + 筛选 tab + 明细表展示;上次结果缓存 localStorage。

- 后端 signal_scan.py(展开/去重取数/信号评估/汇总)+ POST /backtest/signal-scan/run/async
- 只扫信号不重跑回测,不改写策略库业绩快照;单行失败(未知策略/停牌/参数非法)不中断整批
- normalize_symbol 按代码段纠正历史错标市场前缀(与前端 detectMarket 同规则)
- 新增 20 个单测(含与回测引擎成交序列一致性对照),全套 1030 个单测通过
2026-08-21 16:57:12 +08:00
Justin Gu 14debdb446 feat(web-ui): v1.19.7 服务器设置页面(测速+切换通达信服务器)
新增 web UI 第六个页面「服务器设置」,让用户在浏览器上:
1. 列出全部 50+ 候选服务器
2. 一键并发测速(显示延迟和可达性)
3. 点选切换到最快或可用的服务器(热重连,无需重启)

解决不同地区/运营商对通达信各服务器连通性不同的问题。

新增:
- AsyncTdxClient.reconnect_to(host) 热切换方法(持锁,关旧建新)
- GET/POST /api/v1/server/hosts|test|switch 三个端点
- ServerSettingsView.vue 页面(列表+测速+切换)
- 导航栏第六个入口

设计: 先reconnect成功再save_best_host(避免污染config),
host校验只允许候选列表内IP,不自动测速避免首屏卡顿。
2026-07-07 23:08:32 +08:00
Justin Gu c9d80617e8 revert: 移除拼音声母搜索,回到 6 位代码输入
拼音搜索的底层依赖(首次需爬沪深 A 股 5000 条全名单,几十次 TDX 协议
往返,慢机器几十秒到超时)太重,反复优化(按需加载/遮罩/单飞/预热)
都无法兼顾'不阻塞核心行情请求'与'首次可用'。用户决定放弃此功能,
回到简单稳定的 6 位代码输入。

回退 e2bf29e..2523605 共 6 个 commit 的全部改动:
- 删除 StockSearchInput / AppInitOverlay / useStockSearch
- 移除 pypinyin 依赖、/security/search-index 端点、lifespan 预热
- SymbolPicker / StocksPicker 恢复为纯 6 位代码输入
- README / CHANGELOG 同步回退

代码状态等同 v1.18.1(一键寻优多进程并发)发布后的干净基线
2026-07-06 02:50:51 +08:00
Justin Gu 04fd720a05 fix(web-ui): 搜索索引前端超时 15s→120s + 后端单飞去重
问题:另一台机器首次加载报 'signal is aborted without reason'——
不是取不到数据,是前端 AbortController 15 秒就掐断了请求,但遮罩
却告诉用户等 30-60 秒,自相矛盾。

修复:
- 前端 fetchSearchIndex 超时 15s → 120s:遮罩本就是要等的,不能自己掐断
- 后端 _build_search_index 单飞去重:用 asyncio.Future 让 lifespan 预热
  与 /security/search-index 端点请求共享同一任务,避免并发各爬一次全名单
  (两个任务抢同一把 _execute_lock 反而互相拖慢)
- lifespan 预热改为调 _build_search_index(复用单飞),加 120s 超时保护
2026-07-06 02:31:20 +08:00
Justin Gu 9048dfecaa fix(web-ui): 拼音搜索索引改为按需加载,避免首次构建阻塞行情请求
问题:新机器首次打开回测/寻优页时,组件挂载即触发 /security/search-index,
后端要走全量 get_security_list_all(几十次 TDX 协议往返,几十秒)。
而 AsyncTdxClient 是单连接 + _execute_lock,索引构建期间独占连接,
把 /bars 行情请求和寻优请求全部堵在后面,表现为点「一键寻优」后
等好久才出现第一根 bars 请求。

修复(三招组合):
- useStockSearch: 挂载即拉 → 改为显式 ensureLoaded(),只在首次聚焦
  输入框时才触发,确保「打开页面直接点取行情/寻优」的核心路径不被拖累
- fetchSearchIndex: 加 AbortController 15s 超时,避免长时间独占连接
- 静默失败降级:索引拉取失败只记 loadError 显示小 ⚠,不弹错不阻塞
2026-07-06 02:01:47 +08:00
Justin Gu e2bf29e931 feat(web-ui): 股票代码输入支持拼音声母搜索(zjxc→中际旭创)
所有股票代码输入框(回测/寻优/组合页)支持代码/中文名/拼音声母三路
匹配的下拉联想。复用项目里早已有但从未被前端消费的 security_list_all
数据(沪深 A 股 5206 只完整中文名表)。

后端:
- 新增 GET /api/v1/security/search-index 端点,返回 [{code,name,initials}]
- 声母用 pypinyin FIRST_LETTER 预计算,进程内缓存,首次算一次常驻
- web extra 新增 pypinyin>=0.50 依赖

前端:
- 新增 useStockSearch composable(模块级缓存 + 三路过滤 + 防抖)
- 新增 StockSearchInput.vue(下拉 + 键盘导航 + 市场标签)
- SymbolPicker / StocksPicker 接入新组件,保留直接输 6 位代码的快路径

实测 zjxc→中际旭创、gzmt→贵州茅台、cjxc→楚江新材,5000 条本地过滤 <5ms
2026-07-06 01:43:57 +08:00
Justin Gu 05dc9a74af release: v1.17.11 — Web UI 策略库(SQLite 持久化)+ 多策略资金分仓组合回测
新增两层能力:
1. 策略库:单标的/组合回测结果可保存到本地 SQLite 单文件
   (~/.easy_tdx/strategies.db),策略库页可载入回填、重跑、删除。
2. 多策略组合回测:勾选 N 个单标的策略,各拿 1/N 资金、各跑原标的,
   净值曲线按日期并集对齐求和,组合结果含 19 项完整绩效指标 + 持仓表。

后端:strategy_store.py(SQLite CRUD) + multi_strategy_engine.py(资金分仓引擎)
+ routers/strategies.py + /backtest/multi-strategy/run/async。
前端:StrategiesView.vue + 保存策略按钮 + 复用组合页图表组件。

895 单测全绿(+24 新增),ruff/mypy strict/前端 vue-tsc 全通过。
2026-07-04 20:40:57 +08:00
Justin Gu ecd8af1676 feat(web-ui): 取行情整合 + 市场智能识别 + 一键寻优全策略
- 取消单标的/寻优页独立的「取行情」按钮,整合进「开始回测/开始寻测」
  (SymbolPicker 经 defineExpose 暴露 loadBars,父组件串联取数+回测)
- 取消市场手动选择(沪/深/北交所下拉),改为 market.ts 按代码段智能
  识别(17 边界用例验证),代码框旁显示识别结果
- 成交价下拉精简为中文「开盘价/收盘价」,初始资金默认 100 万
- 寻优页 ParamGridPicker 切换策略自动填入预设参数网格
- 寻优页新增「一键寻优所有策略」按钮 + 全局策略排名表
  (OptimizeView 复用 store.runOptimizeAll,结果区含最佳/排名/合计网格点)
- types/api/store 新增 OptimizeAll 契约 + submitOptimizeAllTask
- vue-tsc + vite build 通过
2026-07-04 00:09:05 +08:00
Justin Gu 0cabae4eda fix(web-ui): 翻页拼接后按时间排序,修复>800根数据图表/成交记录错乱
翻页拼接 concat 后页间时间逆序(page1=最新段,page2=更旧段),
导致 index 800 处时间从 2026 倒退到 2019。引擎/图表只正确处理前 800 根,
成交记录在 800 根后出现 2019 年数据。

修复:concat 后加 sort((a,b) => datetime.localeCompare)。
实测 1600 根排序后整体时间正序,index 799→800 连续递增。
2026-07-03 04:30:45 +08:00
Justin Gu 360f836001 fix(web-ui): ECharts 数字两位小数 + 取数自动翻页
图表格式化:新增 format.ts(fmt2/fmtPct),在 KlineChart/EquityChart/
CompareChart/PortfolioCompareChart/OptimizeHeatmap 统一应用——tooltip 用
valueFormatter、axis 用 axisLabel.formatter,所有数值显示两位小数。

取数翻页:fetchBars 当日期跨度超过 800 根时,循环调用 start=0,800,1600...
拼接结果,直到覆盖 startDate 或达上限(10 页 ≈ 32 年日线)。翻页后再按
日期范围闭区间过滤。实测 SZ:000001 翻 2 页拿到 1600 根(2019~2026)。
2026-07-03 04:18:23 +08:00
Justin Gu ff3476f83a feat(backtest): 回测结果对比页
选 2-4 个已完成的回测 task,叠加净值曲线 + 横向指标对比。

后端(最小增量):
- task_runner.list_recent(limit):返回最近 N 个任务摘要(LRU 倒序)
- GET /backtest/tasks?limit=20:任务摘要列表端点(不含完整 result)
- TaskSummary / TaskListResponse schema

前端(/compare 对比页):
- CompareView:左栏勾选已完成 task,右栏叠加对比
- CompareChart:多 task 净值叠加图(归一化为初始=1)
- CompareTable:多 task 指标横向对比表(8 项指标)
- 按 result 结构判断可对比性(仅单标的 BacktestResult 可对比)

复用现有 task_runner LRU 表,无新增存储。测试:823 passed(+2 列表端点)
2026-07-03 04:11:29 +08:00
Justin Gu 87fafe9131 feat(backtest): 参数网格寻优(optimizer + 前端寻优页)
对单个策略的 1-2 个参数做网格搜索,遍历用户指定的取值列表笛卡尔积,
每个组合跑一次回测,按 total_return 排序,返回排名表 + 热力图。

后端:
- ParamGridOptimizer(backtest/optimizer.py):itertools.product 遍历网格,
  每点 entry.build(params) + BacktestEngine.run(df),复用同一 DataFrame
- 网格大小上限 200 防组合爆炸,单点失败容错(跳过不中断)
- 2 参数时生成热力图矩阵(x/y 轴取值 + cell 收益率)
- POST /backtest/optimize/run/async 端点(后台任务)
- OptimizeBacktestRequest schema(param_grid 1-2 参数)

前端(/optimize 寻优页):
- ParamGridPicker:勾选 1-2 个寻优参数,逗号分隔填取值列表
- OptimizeResultTable:网格点排名表(按收益降序,最优高亮)
- OptimizeHeatmap:2 参数热力图(ECharts heatmap,绿→红映射收益)
- 最优点「查看」按钮跳转单标的页用该参数回测

测试:821 passed(+10 寻优器单测 + 3 寻优路由测试)
2026-07-03 03:55:35 +08:00
Justin Gu 6aab7a82b5 feat(web-ui): Vue3 + ECharts 回测前端(单标的 + 组合回测)
独立前端工程(web-ui/),Vue3 + Vite + TypeScript + Pinia + ECharts。
通过 vite proxy 对接后端 /api,开发期无跨域。

单标的回测(/):
- StrategyPicker: 策略下拉 + 按 schema 动态渲染参数表单
- SymbolPicker: 选标的 + 日期范围取行情(默认3年,结束日=今天)
- KlineChart: K线主图 + 买卖点 markPoint(按 datetime 对齐)
- EquityChart: 净值曲线 + 回撤双轴图
- MetricTable: 19 项绩效指标(收益/风险/交易分组)
- TradeTable: 成交记录表

组合回测(/portfolio):
- StocksPicker: 多标的输入(增删标签)
- PortfolioCompareChart: 各标的净值叠加(归一化对比)
- PortfolioSummaryTable: 各标的绩效横向对比
- 顶部导航切换单标的/组合

契约修复(/check 审计):
- fetchBars 归一化 date/datetime 列名(日线返回 date)
- K线买卖点按完整 datetime 对齐(分钟线不再折叠)
- count 上限对齐后端 800
- ECharts 注册内联 dark 主题
- 参数表单空输入不打断编辑
- 网络错误友好提示

技术栈:Vue 3.5 / Vite 8 / TS 6 / Pinia / ECharts(按需引入 725KB)
2026-07-03 03:35:20 +08:00