wshy
eebe533986
Merge pull request #270 from kevin9327/fix/rotation-signal-date-alignment
...
fix(rotation): 轮动信号缺失日按日期归位补齐, 新晋概念不再被误判为退潮
2026-09-09 09:03:54 +08:00
wshy
1b90f57501
Merge pull request #269 from 0112020179/codex/fix-halted-partition-rebuild
...
fix(pipeline): 避免停牌分区反复误删重算
2026-09-09 09:03:49 +08:00
kevin9327
2266ecc1d8
fix(rotation): 轮动信号缺失日按日期归位补齐
...
_compute_rotation_signals 把缺失日的 (999, 0.0) 占位一律追加到序列末尾,
而下游按 ranks[0]=最早日 / ranks[-1]=最新日 解读。概念在部分日期缺席时
(build_rps_rotation 已过滤掉当日无有效 avg_pct 的成员) 实际排名被压到左端、
占位落到右端, 只在最近几日上榜的新晋概念因此被判成退潮。
改为按日期归位补齐, 并补充 tests/test_concept_rotation_signals.py 覆盖
早期缺席 / 最近缺席两个方向。
2026-09-09 07:10:35 +09:00
0112020179
f325a9676c
fix(pipeline): 避免停牌分区反复误删重算
2026-09-08 23:49:55 +08:00
shy3130
9a4bdcd07d
feat(backtest): 环境数据缺口一键补算并自动重跑
...
- 回测报错横幅识别环境数据缺失文案(提取缺失首日), 显示「补算环境数据并重跑」按钮
- 点击后调用已有 /api/regime/recompute 补算缺口区间, 完成后自动重跑本次回测
- 补算请求超时放宽到 5 分钟(需扫全市场 enriched 数据)
- 预热区间不足的报错变体不显示按钮(补算无法解决, 文案自说明)
2026-09-08 22:16:21 +08:00
shy3130
85c903704a
feat(screener): 叠加策略创建与配置体验优化
...
- 新建默认交集合并模式, 选项顺序对调; 可选策略列表加高
- 策略名称默认子策略名用 + 连接, 手动编辑后停止跟随
- 子策略权重改为滑块 (0-100 百分比), 保存时自动按比例归一, 移除手动归一按钮
- 子策略名可点击弹出其配置编辑 (创建对话框与配置对话框均支持)
- 策略池: 叠加策略并入自定义分组并标记「叠加」徽标, 修复误显示为内置
- 创建策略/修改策略池后自动扫描新增日线策略, 免手动刷新
2026-09-08 21:45:38 +08:00
wshy
8cb834d6a1
Merge pull request #267 from 0112020179/codex/fix-neighbor-prefetch-priority
...
fix(frontend): 当前股票加载后串行预取邻股
2026-09-08 21:06:45 +08:00
wshy
cdd41a6d15
Merge pull request #266 from 0112020179/codex/fix-kline-transfer-minute-capability
...
fix(kline): 压缩详情响应并限制无权限分钟回退
2026-09-08 21:06:40 +08:00
wshy
de250f72bc
Merge pull request #268 from kevin9327/fix/pull-window-beijing
...
fix(ext-data): 定时拉取的时间窗口与落盘日期改用北京时间
2026-09-08 21:06:36 +08:00
kevin9327
9a9903cf69
fix(ext-data): 定时拉取的时间窗口与落盘日期改用北京时间
2026-09-08 19:56:03 +09:00
0112020179
cda496ba99
fix(frontend): 当前股票加载后串行预取邻股
2026-09-08 18:46:44 +08:00
0112020179
a8bb7a25bf
fix(kline): 压缩详情响应并限制无权限分钟回退
2026-09-08 18:09:59 +08:00
wshy
a5374d4212
Merge pull request #264 from 0112020179/codex/fix-plugin-source-display
...
fix(frontend): display plugin data source names
2026-09-08 16:53:27 +08:00
shy3130
908b385501
feat(ext-data): 拉取接口支持 API Key 鉴权 + 扩展数据弹窗加宽可滚动
...
后端:
- PullConfig 新增 auth (none/bearer/header/query, 与自定义行情源
AuthConfig 同口径); 拉取/测试/回补共用 _request_json, 鉴权注入
只有一套口径, 用户自定义 Headers 仍优先于 UA 标识头
- Key 本体存 secrets_store (data/user_data/secrets.json, 0600),
不落 config.json; EXT_{ID}_API_KEY 环境变量兜底; 配置了鉴权但
未设 Key 时 fail-closed 拒绝请求
- 新增 GET/PUT /api/ext-data/{id}/api-key (GET 只返回脱敏值);
删除配置时清理残留 Key; 历史 config.json 无 auth 字段读为 None
行为不变; PUT /pull 不带 auth 时沿用现有鉴权
前端:
- 拉取面板新增"接口鉴权"区块: 方式下拉 + 请求头名/参数名 + Key
密码框 (输入新 Key 覆盖, 清空保存删除), 随保存/测试/开关一起生效
- SettingsModal 加 width prop, 扩展数据设置弹窗与 EditExtDialog
加宽至 max-w-2xl; SettingsModal 加 max-h-[88vh] + 内容区独立
滚动, 矮视口下不再被截断
2026-09-07 22:54:05 +08:00
shy3130
f8a23b7ce5
fix(api): quote_service 缺失时 quote-interval 兜底返回默认档位 ( #261 )
...
PUT /preferences/quote-interval 的 if not qs 分支错误调用
qs.get_min_interval(),此时 qs 必为 None,触发 AttributeError → 500。
改为返回硬编码默认值 6.0,与 GET 接口兜底写法及
QuoteService.DEFAULT_INTERVAL 保持一致,并新增复现测试。
2026-09-07 22:01:12 +08:00
0112020179
614e088079
fix(frontend): display plugin data source names
2026-09-07 18:08:40 +08:00
shy3130
cd1cff0089
style(screener): 策略设置对话框加宽 980px → 1200px
2026-09-07 15:26:00 +08:00
shy3130
f03bc38a16
feat(screener): run_all 渐进式返回, 快策略先出、慢策略后台补算
...
策略页全量 run_all 需 ~2 分钟, 期间卡片全空。现在按历史耗时升序执行,
首返时限 (strategy_run_all_first_return_s, 默认 15s) 内算完的策略随
响应返回, 慢策略转后台继续算并逐个写入策略缓存, 前端轮询
cached-summary 逐个点亮卡片数字 (未出的显示脉冲占位)。
后端:
- services/strategy_run_queue: 单飞 daemon 工作线程 + handle 状态。
相同 key (资产/周期/日期/策略集) 且未完成的请求搭车现有执行不重算;
已完成的重跑即新执行。后端全局同时只跑一个 run_all, 补上前端
防重入之外的第二道 Numba 并发防线
- run_all 渐进分支 (仅日线 + summary_only): 逐策略增量写缓存 (同日
按 sid 合并), 收尾整体重写保持旧口径; 结果带 computed_at 时间戳;
分钟周期与明细请求保持整段阻塞不变
- 历史耗时落盘 user_data/strategy_run_timings.json, 次日起快策略自动
排前; cached-summary 透传 computed_at
前端:
- 请求通用 30s 超时 + 慢接口豁免清单 (run_all/run/backtest/factor 等
300s), 避免一个挂起请求占满 HTTP/1.1 连接拖死全站
- Screener: 收到 pending 后 summaryQuery 每 2s 轮询, 以
computed_at >= started_at 判新 (防同日旧缓存冒充), 8 分钟兜底;
StrategyCard 三种尺寸新增 computing 脉冲占位
验证: 新增 13 测试 (排序/落盘/搭车/串行化/端点行为/旧路径兼容),
全量套件 1762 passed; pnpm build 通过。
2026-09-07 15:25:54 +08:00
shy3130
a1ef095334
perf(strategy): run_all 逐策略计时日志与可选并行执行
...
- 每策略计时: ≥1s 用 INFO、否则 DEBUG, 热点策略 (macd_below_zero_revival
~155s / platform_consolidation_breakout ~131s / bullish_alignment ~82s)
可直接从日志定位; 矩阵构建单独计时
- parallel 参数 + strategy_run_all_workers 配置 (默认 1=串行): 实测
2026-09-07 外层 4 worker 并发 41 策略 299.6s 慢于串行 ~112s (polars
eager 内部已多线程, 外层并发属超订), 故默认串行、保留开关供调优
- 叠加策略递归 run_all 固定 parallel=False, 防嵌套线程数爆炸
- 单测: 并行与串行结果/失败语义一致
2026-09-07 15:25:48 +08:00
shy3130
5618b4ef1d
perf(polars): 并发闸+写锁收缩+看门狗三层防死锁, 升级 polars 1.44
...
线上曾出现并发 LazyFrame.collect 触发 polars streaming 执行器死锁,
叠加 _write_lock 区间内做重活, 放大为全站请求冻结。本次按触发缩小、
爆炸半径收缩、自动恢复三层布防:
- polars_guard: BoundedSemaphore 并发闸 (总闸 4 + 后台车道 2, 后台
先拿子闸再拿总闸防死锁); repository 18 处 collect 按交互/后台分级接入
- repository 写锁区间收缩: 分区合并移出锁外, 锁内 (mtime_ns,size)
指纹校验 + 3 次乐观重试, 失败回退锁内合并; 5 处 _write_lock 重构
- watchdog: 周期探测 collect 闸与全局写锁, 连续 2 次失败退出交由
supervisor 拉起 (可配置, 默认开)
- polars >=1.44,<1.45 (1.44.1); 附并发压测脚本
scripts/stress_polars_concurrency.py 供复现验证
另: config 新增 polars_collect_permits / watchdog_* /
strategy_run_all_workers / strategy_run_all_first_return_s 旋钮
(后两者供后续 run_all 优化提交使用, 默认保持旧行为基准)。
2026-09-07 15:25:41 +08:00
shy3130
58b161b16d
fix(enriched): 自愈孤儿 publishing 标记, 步进优化不再误报 publishing
...
清库半删除等异常会留下 owner 已死但状态仍为 publishing 的 generation
标记, 后续读取直接抛 EnrichedGenerationUnavailableError, 步进优化连锁失败。
- 读取侧仅在「owner 是其他进程且该进程已死」时判孤儿并在独占锁内
自愈 (换新 uuid 重建 ready 标记); 同 pid 无活跃对象时保守不判,
避免暴露清库半删除的数据 (fail-closed)
- 回测引擎改为 data_generation_await 轮询等待 (300s 上限), 遇短暂
publishing 自动重试而非直接失败; worker 错误文案同步为可重试提示
2026-09-07 15:25:27 +08:00
wshy
8ef3d66b95
Merge pull request #263 from kevin9327/fix/csv-transcode-streaming
...
perf(ext-data): CSV 编码转换改为分块进行, 峰值内存不再随文件线性增长
2026-09-07 12:27:53 +08:00
wshy
28dbcb0709
Merge pull request #262 from kevin9327/fix/csv-transcode-newline
...
fix(ext-data): CSV 编码转换保留原始换行, 避免最后一列被推断为字符串
2026-09-07 12:27:12 +08:00
kevin9327
6876db1a86
perf(ext-data): CSV 编码转换改为分块进行, 峰值内存不再随文件线性增长
2026-09-07 08:10:38 +09:00
kevin9327
f2fac2e8f0
fix(ext-data): CSV 编码转换保留原始换行, 避免最后一列被推断为字符串
2026-09-07 08:07:02 +09:00
shy3130
4a27dc45d5
fix(docker): 修复容器启动卡死 — uv 锁过期触发运行时重装 + 运行时无镜像源
...
47 服务器部署实测暴露两个连环问题:
1. main 上的 uv.lock 停留在 0.2.2 (pyproject 已 0.2.3), 容器 CMD 是
'uv run uvicorn', 启动时 uv 校验锁不一致 → 在容器内重新锁+重装依赖;
2. uv 国内源 (UV_DEFAULT_INDEX) 只在构建期 RUN 内 export, 未持久化为
ENV —— 运行时重装走默认 pypi.org, 国内网络直连极慢, 容器表现为
零日志不监听。
修复: 重新生成 uv.lock (仅项目版本 0.2.2→0.2.3, 依赖版本不变, 源 URL
改用阿里云镜像); Dockerfile 将 UV_DEFAULT_INDEX/UV_EXTRA_INDEX_URL
持久化为运行时 ENV, 与构建期同源。
验证: 本地 uv run --locked 通过 (锁与 pyproject 一致, 0.2.3)。
2026-09-07 00:34:34 +08:00
shy3130
6ee8e44ce4
fix(docker): USE_CN_MIRROR=1 时 apt 也换阿里云镜像
...
python:3.11-slim 的 sources 指向 deb.debian.org, 部分国内网络(实测
阿里云 ECS)下 apt-get 单阶段耗时 8 分钟以上, 此前仅 npm/pypi 有换源
开关、apt 遗漏(旧注释误以为 debian 镜像已配好源)。补齐 sed 换源,
兼容 bookworm deb822 (debian.sources) 与旧 sources.list 两种格式。
服务器实测: 换源后该阶段恢复秒级。
2026-09-07 00:29:16 +08:00
shy3130
8131cfe853
feat(pipeline): 定时复盘默认 15:40 — 等盘后管道跑完再复盘
...
默认 15:10 的"即时复盘"走实时快照缓存, 不含盘后管道产出的最终口径
(含盘后量校正的日K/enriched)。默认改为 15:40: 盘后管道默认 15:35
启动后留 5 分钟缓冲, 复盘直接使用管道数据。
强制下限仍为 15:00, 偏好即时复盘的用户可自行调早; 存量已保存的
review_schedule 不受影响 (读取不迁移)。
验证: 无本地存储时默认生效 {'hour': 15, 'minute': 40}; prefer/pipeline/
review 相关测试 67 通过; ruff 与 HEAD 一致无新增。
2026-09-06 23:38:55 +08:00
wshy
c39a9b8b17
Update README.md
2026-09-06 23:28:42 +08:00
wshy
957bdd2d25
Merge pull request #259 from 0112020179/codex/hide-missing-intraday-average
...
fix(intraday): hide average when amount is unavailable
2026-09-06 23:27:36 +08:00
shy3130
ddb265b0f8
feat(ext-data): 出站请求默认携带 tsp 标识头
...
扩展数据的三个出站点 (定时/手动拉取与历史回补、内置预设拉取、URL 探测
测试) 统一经 outbound_headers() 注入 User-Agent: tsp/<版本> 与
X-TSP-Client: tick-stock-panel, 服务端 (如 tickflow-hub) 可据此识别
本项目的请求来源。
用户在拉取配置里显式设置的同名请求头优先 (大小写不敏感匹配, 不重复
发送), 需要特定 UA 的数据源不受影响。
验证: pytest 22/22 (含 3 个新用例: 默认标识头/用户头优先/实际请求携带);
逐文件 ruff 与 HEAD 对比零新增。
2026-09-06 23:16:27 +08:00
0112020179
c4b8d44215
fix(intraday): hide unavailable average line
2026-09-06 23:15:21 +08:00
shy3130
d949d9618c
docs(readme): 数据扩展条目补充时序表历史回补
2026-09-06 23:11:36 +08:00
wshy
5805999024
Merge pull request #258 from 0112020179/codex/fix-null-minute-amount
...
fix(intraday): handle missing minute amount
2026-09-06 22:59:49 +08:00
0112020179
471ee6763b
fix(intraday): handle missing minute amount
2026-09-06 22:42:36 +08:00
shy3130
af97df1349
fix(frontend): 分时轮询停表 — 历史日/收盘定版后不再无效轮询
...
自选个股详情弹窗打开即按 6s 轮询分时接口 (StockPreviewDialog), 但两类
场景下数据不可变, 轮询纯属浪费: 周末/翻看历史日期 (后端回退出的历史日
本地分钟K不变), 以及当日收盘定版后。
新增共享停表工厂 minuteRefetchInterval (kline.ts 单一权威):
- source=none / 响应日期 < 北京今天 → 停
- 当日: 收盘根 (≥15:00 的K) 已出现 且 已过 15:30 → 停。
完整性只认收盘根不按根数 —— 实测全天 241 根 (含 09:30 竞价根与
15:00 收盘根), 按根数阈值会在第 240 根 (14:59) 到位时误停, 错过
收盘根; 15:00 后盘后固定价成交可持续到 15:30, 其间量/额仍可能变,
与后端 quote 定版窗口终点 (15:30) 同口径
- 其余 (当日盘中) 照常轮询, 实时性不受影响
StockMultiDayIntradayChart 的最新日查询此前无条件轮询 (无 source=none
停表), 一并接入。判定扫全行取时间标签, 不依赖后端排序契约。
验证: pnpm build 通过。
2026-09-06 22:35:30 +08:00
shy3130
ecbb45b8ef
feat(pipeline): 盘后管道默认 15:35, 与盘后固定价终点 (15:30) 拉开缓冲
...
实测 2026-09-04 数据: 836 只可比标的中 24 只日K量大于分钟K合计 (最大
5.4%), 差额产生于 15:00 收盘后的盘后时段 (盘后固定价/大宗类成交计入
日成交量但不产生分钟K) —— 盘中实时落盘的日K注定缺失该尾巴, 只有
15:30 之后的官方日线才完整。
- 默认调度 15:30 → 15:35: 避开供应商日线未定稿窗口, 也与 quote 定版
重试窗口终点 (15:30) 不再精确重合
- set_pipeline_schedule 保存下限从 15:00 收紧到 15:35 (存量已存配置
不迁移, 读取不钳制, 仅下次显式保存时生效)
- 定时复盘默认 15:10 (即时复盘走实时快照缓存, 不依赖管道) 刻意不动
验证: set 钳制冒烟 (15:30→15:35, 15:35/15:36 原样); ruff 与 HEAD 基线
一致无新增; pytest prefer/pipeline/daily 相关 128 通过。
2026-09-06 22:35:24 +08:00
shy3130
cd9e20610f
feat(ext-data): 时序表历史回补 — date_param 按日拉取 + tickflow-hub 404 契约
...
人气排行等 timeseries 扩展表此前只能从开启拉取之日起逐日累积。拉取配置
新增日期参数名 (date_param), 接口支持按日查询时即可历史回补: 按本地交易日
逐日请求 ?{date_param}=YYYY-MM-DD 写入对应分区, 幂等 (已有分区跳过),
单次上限 120 天, 429 限流退避重试 + 连续限流中止可续补。
适配 tickflow-hub PR#19 (/exports、/fuyao-rank 按日历史截面):
- 该日无快照返回 404 → 计入 empty 跳过, 不进失败清单 (主循环与 429
退避重试两条路径均覆盖)
- 防污染契约: 响应行 date 与请求日期不一致 (接口忽略日期参数) 时
fail-closed 拒写该分区, 避免当日值污染整个历史时序
- 修复调度器 next_run 计算的 UTC 未导入 NameError
前端拉取面板新增日期参数名配置与回补入口; 回补落盘的历史数据立即进入
信号/因子/回测按日对齐通道 (PIT)。
验证: pytest tests/test_ext_backfill.py 16 通过 (含 404/429/幂等/防污染),
ext 全套 144 通过; pnpm build 通过。
2026-09-06 22:35:08 +08:00
shy3130
537728a870
docs(plugin-dev): 修正 volume 单位契约为「手」( #195 )
...
契约表与 get_realtime 字段表原标注 volume 单位为「股」,与项目实际口径不符
(日K/实时快照均为手,股票/ETF/指数一致,与上游 TickFlow 一致)。
复核方法: 对 135 根日K 做 VWAP 区间检验(amount÷volume÷100 均落在当日
[low,high] 内,「股」假设 0/135 通过),确认 issue #195 所述 ETF 与 A股
单位不一致不存在,已按非缺陷关闭。契约表补充单位自验方法与 provider
显式换算要求(上游给股时 /100,参考 fuyao)。
2026-09-06 21:56:11 +08:00
wshy
f275edafeb
Merge pull request #256 from SummerCaptain/feat/recap-push-gate
...
feat(preferences): 复盘推送 review_push_mode 门控
2026-09-06 20:53:29 +08:00
wshy
f0c0fd3bf8
Merge pull request #255 from SummerCaptain/feat/ai-strategy-draft-gate
...
feat(strategy): AI 策略保存为 research_only 草稿 + publish 端点
2026-09-06 20:53:25 +08:00
wshy
c94fe2bf31
Merge pull request #251 from 0112020179/codex/fix-fuyao-history-oom
...
修复扶摇历史日K同步内存溢出
2026-09-06 20:53:22 +08:00
shy3130
e3a2fbce13
feat(ext-data): 扩展表字段接入信号与因子(数值因子/评分 + string 归属筛选)
...
数值字段(int/float) → 信号+因子双通道:
- ext_factors: 帧组装时 join 扩展列并注册 kind=base 因子(分组「扩展数据」),
时序模式按 (symbol,交易日) 精确对齐无未来函数, 快照模式仅当日单日帧
注入(历史帧跳过防未来函数)
- registry.all_factors 惰性同步(配置目录签名幂等, 以注册表为权威增删);
custom_signals.allowed_fields 自动并入 → 信号下拉/因子库/AI提示词/检验
同一份清单; factor 补算入口按需注入
- 失效链: 上传/拉取/配置变更自动清扩展帧缓存+策略缓存, API层补
repo.clear_cache; 写入后下一次计算立即生效
- 列名保留中文(预设表字段名), 非ASCII数值字段只进信号不注册因子
(DSL标识符ASCII-only)
string 字段(概念/行业归属) → 仅信号条件通道:
- 运算符 包含(contains,字面量匹配非正则)/等于/不等于, 右值为字符串字面量,
可与数值条件混合(强势板块归属 AND 热度阈值)
- 前端信号编辑器按字段类型切换运算符与右值输入; /options 暴露
stringFields; AI 提示词含字符串字段清单与 contains 用法
- string 不注册为因子(数值口径), 空值不误报
测试: test_ext_factors 18个(PIT对齐/跨日不泄露/快照门控/写入失效/
contains字面量/中文列名端到端等); 存量因子计数测试补 data/ 运行时隔离
夹具(黄金断言不依赖本机扩展表); 受影响回归148个全过; pnpm build 通过;
ruff 对齐 main 基线
2026-09-06 18:27:33 +08:00
shy3130
716897f41a
feat(signals): 信号库新增盘中信号(分钟K特征)
...
- intraday_features: 会话对齐特征帧构造器(vwap/涨跌幅/1·3·5分钟放量比/
日内与开盘30分钟高低点距离, 滚动窗口不跨午休, 只用已收盘bar防未来函数)
- custom_signals: timeframe=daily|intraday 双 schema, 盘中条件支持
cross_up/cross_down 穿越算子; 输出为当日条件上升沿(首bar不触发,
null特征判false绝不误报)
- 旧4个分时穿越信号列名零迁移(评估器回映射历史列名, 存量监控规则不动)
- 引擎单点注入 csgi_ 列: 监控/分钟策略/分钟回测共用同一构造器;
日线策略引用盘中信号显式报错
- 回放验证 API /api/custom-signals/intraday/replay(本地历史分钟K重放,
区间≤60天标的≤200, 先验证再配置监控)
- 能力门槛: 分钟K能力(订阅池)或全量分钟能力(本地分区); 回放仅需本地历史
验证: 新增16个测试(特征数值/边界/旧4信号黄金等价/引擎注入/回放端点),
受影响回归109个全过, ruff对齐基线, docs/features.md 同步
2026-09-06 18:26:29 +08:00
0112020179
3d6beb3c35
fix(fuyao): 根据审查完善流式同步
2026-09-06 17:39:43 +08:00
sc
9d55c237ed
feat(preferences): review_push_mode 端点与前端开关配套
...
- settings: GET 返回 review_push_mode, PUT review-push 支持 mode 入参
- market_recap: push 移入 SaveReportRequest body(显式外发)
- Review 页: 推送触发方式 auto/manual 开关
- 门控测试: 手动/定时两条路径的 manual/auto 推送断言
2026-09-06 16:20:42 +08:00
sc
e6c7fa4a43
feat(strategy): 策略池 AI 草稿分区与发布闸前端配套
...
- 后端 publish 失败由 ValueError 改为 HTTPException(500) 返回给前端
- 策略池 AI 标签新增「草稿」分区, 展示 research_only 策略并提供发布按钮
- 导入/保存 AI 策略为草稿时提示发布后可用, onSavedId 对草稿态跳过入池校验
2026-09-06 16:05:02 +08:00
sc
905fb8846c
feat(preferences): 复盘推送 review_push_mode 门控
2026-09-06 13:41:52 +08:00
sc
f6fc22fef1
feat(strategy): AI 策略保存为 research_only 草稿 + publish 端点
2026-09-06 13:41:51 +08:00
0112020179
1c022a1c7c
fix(fuyao): 流式同步历史日K避免内存溢出
2026-09-06 12:35:26 +08:00