4 Commits
Author SHA1 Message Date
shy3130 9593883c59 refactor(strategy): 分钟红7由内置策略改为自定义策略
按用户要求, 分钟红7不再是产品内置形态, 以自定义策略形态交付:
- 移除 app/strategy/builtin/minute_red_streak.py; 运行时副本落在
  data/strategies/custom/ (gitignore, 用户可自行修改调参)
- 策略 id (minute_red_streak) 不变: 参数覆盖 / 策略池引用 / minute_filter
  契约 (daily_history_bars + daily= 注入) 全部不受位置影响
- 仓库保留参考实现作为测试夹具 (tests/fixtures/strategies/),
  25 个行为测试改由夹具加载, 引擎加载测试同时断言 source == "custom"
- builtin 相关不变量更新: 内置 19 个全部 matrix_native, 无 minute_filter

本地验证: /api/strategies/reload 后 source=custom, 08-25 分区分钟扫描
命中 5 只 (用户实盘参数: 6根开5红+最高2红+20日涨停过+沪深主板50-200亿)。
2026-08-30 19:05:11 +08:00
shy3130 b82c4eaedb feat(minute): 分钟红7新增「N日内涨停过」条件 + minute_filter 日线窗口契约
分钟策略此前只能访问当日分钟窗口, 无法叠加日线维度条件。本次为
minute_filter 后端扩展可选日线历史契约:

- 契约: 策略声明 META["daily_history_bars"] (0-250) + filter_minute_history
  接受 daily 关键字 (加载期校验, 纯分钟策略零改动); 引擎聚合各策略声明
  (minute_daily_history_bars) 后由 ScreenerService 1m 分支装配
  context.daily_history (enriched 日线窗口), run() 以 daily= 注入
- 分钟红7: require_limit_up (默认开) + limit_up_days (5-60, 默认20) 参数;
  涨停判定复用 enriched 预计算信号 signal_limit_up (收盘封板) 或
  signal_broken_limit_up (炸板盘中触及), 任一命中即算涨停过, 输出
  recent_limit_ups 次数列; 日线窗口缺失时失败闭合 (宁可漏过不可错报)
- 测试 25 项: 涨停信号过滤/炸板计数/回看窗口边界(第20日含第21日不含)/
  失败闭合/开关旁路/加载校验(缺 daily 关键字与超范围)/引擎注入/服务装配

实盘验证: 用户参数(bars=6)基线 24 只 → 要求涨停过后 6 只, 全部带
recent_limit_ups; 全量 1112 项后端测试通过。
2026-08-30 19:05:09 +08:00
shy3130 1746a0e305 feat(minute): 分钟红7改用开盘窗口 + 盘中增量卡片移至设置右列
分钟红7: 检查窗口从「最近7根」改为「当日最早7根(开盘7根)」—
捕捉开盘急拉形态, 窗口在早盘即固定, 不随盘中新K线漂移;
close 取开盘窗口末根收盘价 (基础过滤口径同步更新)。

- 窗口选择: tail → head (sort 后 int_range < bars), 输出列契约不变
- 新增两个区分性测试: 开盘命中后转绿仍命中且 close 取窗口末根;
  开盘不足红K数、尾盘转红不救回 (旧最近窗口口径会命中)
- 实盘验证: 252 只命中, 每只窗口末时间均为 9:36 (开盘第7根)
- 设置页「盘中分钟增量」卡片从左列顶部移至右列 (连板梯队修正之后)

注: 本地 runtime 覆盖文件 minute_red_streak.json 的 description
快照已同步新文案 (gitignored, 不入库)
2026-08-30 19:05:07 +08:00
shy3130 5e2358ce48 feat(minute): 分钟策略执行后端 + 分钟红7策略 + 盘中增量落盘 (Expert)
一期 · 分钟策略执行链路:
- 引擎新增 minute_filter 执行后端: 策略声明 filter_minute_history(df, params),
  timeframes 必须且仅为 ["1m"]; 输入为当日分钟K窗口, 命中行事后联表 enriched
  快照补基础过滤列 (name/total_shares/change_pct), close 用最新分钟价
- 内置策略「分钟红7」(minute_red_streak): 最近 N 根(默认7)分钟K至少 5 根
  close>open, 且按最高价排序的最高的 2 根全红; 全向量化, 671k 行约 230ms;
  参数 bars/min_red/top_red/rank_by_close, 不足 N 根不触发, 同值取更晚K线
- ScreenerService 1m context: 优先读 as_of 当日 kline_minute 分区, 缺失回退
  全市场最近分区; 单分区直读与全量 glob 解耦
- run_preset/run_all 分钟周期结果不写日线盘后缓存 (语义隔离)

二期 · 盘中分钟增量落盘 (Expert 专有):
- kline_sync.fetch_intraday_full_market_burst: intraday.batch 独立限流池,
  全市场 5546/200=28 块线程池一次打出, 轮内不重试
- MinuteRefreshService: 后台线程, 门控链 = 开关→自定义分钟源让位→INTRADAY_BATCH
  能力→连续竞价时段(9:30-11:30/13:00-15:00); 固定节奏 next=max(起点+间隔,完成),
  不补跑; 每轮单次合并落盘 (_write_minute_partition unique 幂等)
- 偏好 minute_refresh_enabled(默认关)/minute_refresh_interval([60,300]s 默认60);
  GET /api/settings/minute-refresh/status 状态端点

前端:
- 策略页日线/分钟周期切换 (1m 下 ETF 置灰、不触发盘后 runAll、prune 仅日线),
  策略卡片「分钟」徽章, 策略池对话框按周期拉取
- 数据页分钟K设置弹窗新增盘中增量区块: 开关/间隔(60-300s)/能力缺失置灰/
  服务状态行(运行中·时段暂停·最近一轮)

测试: 26 项新增 (形态7/引擎4/context4/服务11), 更新 3 个 matrix 不变量测试;
全量 1112 passed; 前端 build 通过; 浏览器端到端实测通过
2026-08-30 19:05:05 +08:00