| name | invest-a-gap-scan |
| version | 0.2.7 |
| description | 跳空缺口扫描 — 向上缺口 + MA60 上方 + 未回补,指数成分股池(沪深300+中证A500+科创50)触发词:缺口/跳空扫描 |
| whenToUse | 缺口/跳空扫描:向上跳空缺口 + MA60 上方 + 未回补的成分股筛选 |
| argument-hint | /invest-a-gap-scan [--gap-min-pct 1.5] [--gap-min-vol-ratio 1.5] |
| allowed-tools | Bash, Read, Write, WebSearch, WebFetch |
| user-invocable | true |
| metadata | {"requires":{"bins":["uv","python3"]},"optionalEnv":["TUSHARE_TOKEN"]} |
invest-a-gap-scan 跳空缺口扫描
工具约束说明:frontmatter 的 allowed-tools 是 Claude Code 约定;在 DSH 等不读取该字段的 harness 下不生效,实际可用工具由平台自身沙箱控制。本技能主体操作为本地数据采集与计算(Bash/Python 引擎);部分维度经 WebSearch/WebFetch 补充检索
概述
扫描沪深300 + 中证A500 + 科创50 成分股并集(去重后约 450~500 只),找出同时满足:
- 近 60 个交易日内有向上跳空缺口(
low[i] > high[i-1],幅度 >= 1%)
- 自缺口日起至今收盘始终在 MA60 上方(
close[t] >= MA60[t] for all t >= gap_idx)
- 缺口形成后最低价从未回补至上沿及以下(
min(low[gap_idx+1:]) > gap_high)
缺口定义
gap_high ─────── low[i] (缺口上沿 = 跳空日最低价)
|
gap_pct = low[i] / high[i-1] - 1
|
gap_low ─────── high[i-1] (缺口下沿 = 前日最高价)
- 未回补: 缺口形成后所有交易日的最低价均 > 缺口上沿
- 跨停牌: 缺口前一交易日为停牌日 -> 单独列出,不参与常规排序
筛选漏斗
478 只成分股经过多层筛选的典型分布:
478 只成分股
|-- ~200 (43%) 无缺口 -- 60 日内无 low[i] > high[i-1]
|-- ~110 (23%) 低于阈值 -- 有缺口但幅度 <1%
|-- ~130 (27%) MA60 破 -- 缺口后收盘跌破 MA60 (最大淘汰项)
|-- ~17 (4%) 缺口回补 -- 最低价回补至上沿
|-- ~6 (1%) 低流动性 -- 20 日均额 <1 亿
|-- ~1 获取失败
-------------------------------------
~5 (1%) 命中
运行
基本用法
cd "${INVEST_SKILLS_ROOT:-.}" && uv run python skills/invest-a-gap-scan/scripts/scan.py
参数表
| 参数 | 默认 | 说明 |
|---|
--universe | csi300,a500,star50 | 指数池,逗号分隔,支持空格 |
--gap-min-pct | 1.0 | 缺口幅度阈值 %。low[i]/high[i-1]-1,<1% 归为"低于阈值"淘汰 |
--gap-lookback | 60 | 缺口回溯交易日数。只搜索最近 N 根 K 线中的缺口 |
--gap-min-vol-ratio | 1.0 | 缺口日成交额 / 20 日均额下限。1.0=不过滤,>1.0=要求放量 |
--min-avg-amount | 100000000 | 20 日均额门槛(元)。<1 亿归为"低流动性"排除 |
--min-list-days | 60 | 最少 K 线根数。不足的标的归为"上市不足"排除 |
--top | 30 | stdout 命中表格行数(md 报告始终全量) |
--source | auto | 数据源:auto(优先 Tushare)/tushare/baostock |
--no-cache | off | 强制刷新 K 线缓存 + 成分股缓存 |
--universe-limit N | 无 | 只扫前 N 只(开发调试用) |
--no-save-report | off | 不写入 reports/gap-scan/ 目录 |
--json | off | stdout 输出 JSON 格式 |
示例
cd "${INVEST_SKILLS_ROOT:-.}" && uv run python skills/invest-a-gap-scan/scripts/scan.py --gap-min-pct 2.0
cd "${INVEST_SKILLS_ROOT:-.}" && uv run python skills/invest-a-gap-scan/scripts/scan.py --gap-min-vol-ratio 1.5
cd "${INVEST_SKILLS_ROOT:-.}" && uv run python skills/invest-a-gap-scan/scripts/scan.py --source baostock
cd "${INVEST_SKILLS_ROOT:-.}" && uv run python skills/invest-a-gap-scan/scripts/scan.py --universe-limit 30
cd "${INVEST_SKILLS_ROOT:-.}" && uv run python skills/invest-a-gap-scan/scripts/scan.py --json
cd "${INVEST_SKILLS_ROOT:-.}" && uv run python skills/invest-a-gap-scan/scripts/scan.py --no-cache
算法详解
容忍规则 (Tolerance Rule)
缺口按从新到旧排序,遇到第一个满足全部条件的即命中:
for gap in qualified_gaps (newest first):
if MA60 从未跌破 since gap_day:
if gap 从未回补:
if 量比 >= gap_min_vol_ratio (如启用):
-> 命中
else:
-> 继续检查更老的缺口 (量比不够)
else:
-> 继续检查更老的缺口 (已回补)
else:
-> 继续检查更老的缺口 (MA60 已破)
不回退到已回补的缺口。这意味着:如果最新缺口已回补但更老的缺口未回补且 MA60 完好,会命中老缺口。
跨停牌缺口
停牌检测基于交易日历 + 日线数据对比:某个交易日在 trade_cal 中存在但该标的不在 daily_by_date 中 -> 标记为停牌。缺口前一交易日为停牌日 -> 归入 across_suspension_hits,不参与常规排序。
注意: 无 Tushare token 时使用自然日估算交易日历(Mon-Fri),此时跳过停牌检测以避免假期误判。
MA60 计算
使用 invest-a-stock 的 lib.technical.sma(60 日简单移动平均)。前 59 个位置 MA60 为 None,_check_ma60_streak 跳过 None 值。NaN close 触发 MA60 失败(利用 not (NaN >= MA60) 恒为 True 的特性)。
前复权 (QFQ)
- Tushare 路径: 原始价格 x
adj_factor / latest_adj_factor -> 以最新日为基准的前复权价格
- Baostock 路径:
adjustflag="2" 直接返回前复权价格,无需额外计算
两种路径的 QFQ 算法存在细微差异,因此缓存按数据源隔离 ({kline}/{source}/{ts_code}.pkl)。
数据流
1. build_universe() 指数成分股并集 -> 去重 + ST/退市过滤 -> ~478 只
|
2. create_source("auto") 有 Token -> TushareBulkSource (按日批量)
无 Token -> BaostockSource (逐股查询)
|
3. _fetch_trade_cal() Tushare trade_cal API -> 真实交易日历
失败 -> 自然日估算 (Mon-Fri, 跳过停牌检测)
|
4. kline_cache.load() 命中 -> 跳过拉取
未命中 -> fetch_daily_batch + build_stock_kline + cache.save
|
5. detect_suspensions() 对比 trade_cal vs daily_by_date -> 停牌日期列表
|
6. scan_all() 逐股: 流动性排除 -> 找缺口 -> 容忍规则 -> 命中/排除/未命中
|
7. format_brief() 命中表 (缺口幅度降序) + 排除/未命中统计
format_markdown_report() 详文档 -> reports/gap-scan/{yyyymmdd}.md
数据量
| 项目 | 数量 |
|---|
| 交易日范围 | ~180 自然日 (~120 交易日,gap_lookback + 59 bar 确保 MA60 全覆盖) |
| 成分股 | ~478 只 (去重后) |
| K 线行数 | ~57,000 行 |
| 缓存磁盘 | ~25 MB (477 个 pickle 文件) |
性能
| 场景 | 耗时 | 说明 |
|---|
| 首次扫描 (Tushare) | ~4 min | 按日批量 API(~120 日),受限于 Tushare 限速 |
| 首次扫描 (Baostock) | ~5 min | 逐股查询,每只 ~0.6s,~120 日数据 |
| 同日二次扫描 | ~7s | 全部缓存命中,仅做缺口算法 |
| 部分缓存命中 | ~7s + 缺失部分拉取 | 只拉取未命中标的 |
输出
stdout 摘要
========================================================================
invest-a-gap-scan v0.2.7 -- 跳空缺口扫描
========================================================================
池构成: 沪深300(300) + 中证A500(500) + 科创50(50) -> 去重 478 只
数据源: baostock (前复权 adjustflag=2) (前复权)
覆盖率: 99.8% (477/478 有K线) | 命中: 5 只 | 跨停牌: 0 只
参数: 缺口>=1.0% | 回溯60日 | MA60 | 日均额>=1.00亿
排除: 获取失败 1 | 低流动性 6
未命中: 无缺口 207 | 低于阈值 111 | MA60破 131 | 缺口回补 17
| 代码 | 名称 | 指数 | 板块 | 缺口日 | 缺口% | 缺口区间 | 现价 | MA60 | MA60% | 距上沿% | 量比 | 20日均额 |
|-----|------|-----|-----|--------|------|---------|-----|------|------|--------|-----|---------|
| 300628.SZ | 亿联网络 | 300 | 创业板 | 20260715 | +4.62% | 33.96~35.53 | 36.71 | 35.64 | +3.00% | +3.32% | 2.15 | 4.40亿 |
命中表列说明
| 列 | 含义 |
|---|
| 代码/名称 | 标的 |
| 指数 | 所属指数 (300=沪深300, 500=A500, 50=科创50) |
| 缺口日 | 缺口形成日期 |
| 缺口% | 跳空幅度 |
| 缺口区间 | 缺口下沿~上沿 (即回补位参考区间) |
| MA60% | (现价 - MA60) / MA60,正值=MA60 上方 |
| 距上沿% | (现价 - 缺口上沿) / 缺口上沿,正值=远离缺口,负值=已回补 |
| 量比 | 缺口日成交额 / 20 日均额,>1=放量 |
| 20日均额 | 近 20 日平均日成交额 |
详文档
reports/gap-scan/{yyyymmdd}.md: 全量命中表 + 逐股简析(含催化待查提示)+ 排除/未命中统计 + 运行参数。
缓存
位置
~/.local/share/investment/gap_scan_cache/
|-- universe_20260719.pkl (成分股列表, 28 KB)
|-- kline/ (固定段键目录, v0.2.5)
| |-- tushare/ (按数据源隔离)
| | |-- 000001.SZ.pkl
| | `-- ...
| `-- baostock/
| |-- 000001.SZ.pkl
| `-- ...
缓存策略
- TTL: 3 天 (基于文件 mtime;固定段键使跨日命中生效,旧版
{YYYYMMDD} 日期目录随 v0.2.5 一次性清理)
- Scope: 按数据源隔离,tushare/baostock 缓存互不污染
- 格式: Python pickle (pandas DataFrame)
- 强制刷新:
--no-cache 跳过加载,重新拉取并覆盖
数据源
| 来源 | 需要 | 用途 |
|---|
| Tushare Pro | TUSHARE_TOKEN (>=120 积分) | K 线 (批量按日) + 复权因子 + 交易日历 |
| baostock | 无 (默认兜底) | K 线 (逐股, 前复权 adjustflag=2) |
| akshare | 无 | 指数成分股 (index_stock_cons) |
降级策略
auto:
1. 检查 TUSHARE_TOKEN -> 有 -> TushareBulkSource (快速批量)
2. 无 -> BaostockSource (逐股兜底)
交易日历:
1. Tushare trade_cal API -> 真实日历 + 停牌检测
2. 失败 -> 自然日估算 (Mon-Fri) + 跳过停牌检测
排除/未命中原因
排除 (扫描前剔除)
| 原因 | 含义 |
|---|
| 获取失败 | API 拉取失败或网络错误 |
| 低流动性 | 20 日均额 < --min-avg-amount |
| 上市不足 | K 线根数 < --min-list-days |
| 数据缺失 | 缺少复权因子 (仅 Tushare 路径) |
| ST | ST 标的 (名称含 "ST") |
| 退市 | 退市标的 (名称含 "退") |
未命中 (扫描后无结果)
| 原因 | 含义 |
|---|
| 无缺口 | 回溯窗口内无 low[i] > high[i-1] |
| 低于阈值 | 有缺口但幅度 < --gap-min-pct |
| MA60破 | 缺口后某日收盘 < MA60 |
| 缺口回补 | 缺口后最低价触及或跌破缺口上沿 |
| 量比低 | 缺口日量比 < --gap-min-vol-ratio (仅 >1.0 时生效) |
联动
对命中的标的,接 /invest-a-stock {symbol} 做深度基本面研究。
合规
- 禁止买卖/仓位建议
- 禁止单一目标价
- 用「缺口区间 / 上沿回补位」等中性表述
- 输出末尾标注"仅供研究,不构成投资建议"