公募基金持仓数据分析(全景报告流水线)
Overview
为一支任意公募基金生成"持仓变化全景分析"HTML 报告:覆盖 2023Q1 至最新季度的逐季持仓变化,包含三页签版面(01 基金概览 / 02 仓位与配置结构 / 03 持仓个股深度)、8 维综合评分雷达图、基金经理投资方法论模块、个股买卖点复盘。整套流水线由 scripts/ 中的通用脚本驱动,仅需传入基金代码即可运行。
核心产出(最终 HTML 报告的模块结构)
报告固定三页签(Tab)结构,页签导航 .tab-nav/.tab-btn 必须放在所有 .tab-pane 之外(118001 曾踩坑:导航放进 p1 内部导致切换后消失):
- 01 基金概览:核心指标速览(4 张 summary-card)→ 基金经理选股能力点评(蓝名片)→ 优点(黄卡)/不足(绿卡)→ 基金综合评分(8 维雷达 + 明细表)→ 基金经理投资方法论(人物名片 + 能力卡片 + 持仓验证 + 最新观点)
- 02 仓位与配置结构:一、权益仓位变化(蓝色渐变柱状堆叠图);二、前十大持仓板块结构(主板/创业板/科创板/港股通纯色堆叠图);三、行业配置变化(暖冷交替渐变堆叠图)
- 03 持仓个股深度:四、前十大逐季变化(季度页签表格);五、核心个股权重追踪(≥3 季折线图);六、个股进出时间线;七、个股股价走势与买卖时点(点击个股标签切换);八、全部个股买卖点汇总表
数据流水线(scripts/,按顺序执行)
每个基金一个工作目录 <fund_code>/(如 019032/),内含 pdfs/、prices/ 子目录。所有脚本均已"通用化"——季度窗口从 dc_parsed.json 的键((\d{4})Q([1-4]) 正则)动态推导,新季度/新基金无需改日期字典。
# 1. 下载季报 PDF(东财公告接口,输出 pdfs/YYYYQX.pdf)
python download_pdfs_generic.py <FUND_CODE> <WORK_DIR> [--start-year 2023]
# 2. PDF 表格抽取(pdfplumber → dc_tables.json)
python extract_tables_generic.py <WORK_DIR>
# 3. 语义解析(dc_tables.json → dc_parsed.json,v2 语义扫描)
python parse_generic.py <WORK_DIR>
# 4a. 个股行情拉取(westock CLI,周线前复权 → prices/{sh|sz|hk}XXXXX.json)
python fetch_prices_generic.py <fund_dir>
# 4b. 基金净值 + 滚动收益 + 最大回撤(东财 API → nav_growth.json)
python fetch_nav_generic.py <FUND_CODE> <WORK_DIR>/nav_growth.json
# 5. 数据整合(dc_parsed.json + prices → dc_report_data.json)
python gen_report_data_generic.py <fund_dir>
# 6. 报告生成(需先配置 fund_config_template.py → fund_config.py)
python build_html_generic.py <FUND_CODE>
环境依赖:python 3.13(managed venv)、pdfplumber、westock CLI(C:\Users\高志琛\.local\bin\westock.exe)。ECharts 走 CDN(cdn.jsdelivr.net)。
关键数据口径(必须遵守)
- 个股收益(买卖点口径):
- 多季度持仓:买入价 = 进入季度末收盘价,卖出价 = 退出季度末收盘价(前复权)
- 单季度持仓(n_quarters == 1):买入价 = 进入季度初第一个收盘价(否则买入=卖出导致收益恒为 0),卖出价 = 退出季末收盘价
- 仍持有:用最新价算浮盈;
ret为(exit/entry - 1) * 100或(last/entry - 1) * 100
- 市场/板块判定:5 位数字代码 = 港股(
hk前缀 + zfill(5));688/689开头 = 科创板;300/301开头 = 创业板;6/9开头 = 沪市(sh);其余 = 深市(sz);A股 6 位代码 +market=='港股'→ 港股通 - A/H 双重上市(如中芯国际):按代码区分保留为两条记录,不合并
- 核心个股 = 出现 ≥ 3 个季度的个股(用于权重追踪折线图)
- 行业配置:A 股部分用证监会行业分类(字母代码行),港股部分单独统计
hk_total(含"港股通合计"行) - 季度窗口:默认 2023Q1 起至最新季度;QDII 基金(如 118001)无 A 股板块概念,保留"市场(国家/地区)分布"图结构,仅统一配色,不要强行改成板块结构图
8 维综合评分体系(fund_config 中配置)
| 维度 | 权重 | 数据来源 | |---|---|---| | 获利能力 | 25% | nav_growth.json 滚动收益(过去1年/3年/单季) | | 个股胜率 | 20% | stocks[].ret:盈利占比、平均收益、最大亏损、单季波段胜率 | | 方法论成熟度 | 15% | 基金经理公开框架与持仓行为交叉验证 | | 进攻弹性 | 10% | 单季爆发、重仓股期间收益 | | 行业配置 | 10% | 行业集中度与迁移路径 | | 回撤控制 | 10% | nav_growth 最大回撤_近3年 | | 风险分散 | 5% | 前十大集中度、行业单一度 | | 规模适配 | 5% | 规模 vs 策略容量 |
- 总分 = Σ(score × weight),四舍五入取整;评级区间:90+S|80-89 A|70-79 B|60-69 C|<60 D
- 评分必须引用真实统计数据(
locals()注入 build 环境,在 fund_config 的 basis 中可用{avg_ret}、{win_rate}等变量),并注明"季度自动更新后需复核调整" - 评分条视觉:≥60 分红渐变(
linear-gradient(90deg,#ef9a9a,#c62828)),<60 分绿渐变(#a5d6a7→#2e7d32);评分卡渐变#8e2a2a→#c62828
报告质量校验(交付前必须执行)
# 结构校验:div 平衡、占位符残留、雷达值与总分匹配、__DATA__ 可被 json.loads
python _check_html.py # 需先按基金代码/文件名更新 files 字典
校验规则:
re.findall(r'<div[ >]')数量 ==</div>数量(否则页签结构损坏,p2/p3 嵌套进 p1)- 无
__[A-Z_]+__占位符残留 - 雷达图
value:[...]与总分、各维度评分一致 const R = {...}可被json.loads解析- 图表用色无蓝色主题残留(旧版 #1a237e/#3949ab 等)——若改造旧报告需检查
常见坑(历史踩过,勿重蹈)
- 页签导航必须在所有 tab-pane 外层,否则切换后导航消失
- display:none 容器内的 ECharts 图表:切回时需
echarts.getInstanceByDom(el).resize(),否则 0 宽(build_html_generic.py 的 switchTab 已处理,勿删) - PDF 表头含换行符:匹配表头前需
.replace('\n','');跨页续表用 top_ctx 状态识别,债券代码表出现时重置 - 东财净值 API 每页固定 20 条(pageSize 参数失效),需按 TotalCount 翻页;季度末无净值时取 ≤ 目标日最近净值
- westock 港股代码:
hk+ 5 位数字(zfill) - 单季度持仓收益为 0:一定是买入价取错(见口径 1)
- 脚本改文件后如需 Edit 手工修补:必须先重新 Read,否则报 "File has been modified since read"
- 118001 类一次性改色脚本(recolor)非幂等,不可重复执行;build_html_generic.py 幂等可重跑
资料库导入(可选,覆盖更新)
# 前置:runtime_context 判定 mode → ToolSearch 找 connect_open_platform → DeferExecuteTool 取 token(--token-stdin)
# 图片外链自检:grep -Eoi '<img[^>]+>' <html> | grep -E 'codebuddy|workbuddy' 必须为空
python page/import_html.py "<html路径>" --token-stdin --space-id AgzYk9MPCymn0WlK0rFMab [--node-block-id <id>]
- 带
--node-block-id= 覆盖更新(链接不变);不带 = 新建 - 导入后返回
KS_IMPORT_OK+ node id + 链接
References
references/methodology.md— 分析思考方法详解:如何解读一份季报、逐季变化叙事逻辑、评分依据撰写、基金经理方法论梳理方法、QDII 基金特殊处理references/style-guide.md— 通用深红暖色风格规范:全部 CSS 变量与 7 类图表的精确配色
Scripts
download_pdfs_generic.py/extract_tables_generic.py/parse_generic.py/fetch_prices_generic.py/fetch_nav_generic.py/gen_report_data_generic.py/build_html_generic.py/_check_html.py— 完整流水线(用法见上文)fund_config_template.py— 新基金必须适配的配置文件:FUND_CONFIG[code] 含 name_cn/short_name/subtitle/info_extra/manager_comment/merits/weakness/score_dims(8维)/total_score/grade/score_desc/method_html(方法论HTML)/cards_html(4张速览卡)/insight_equity/insight_board/insight_industry(三条洞察文案)。参考其中 4 只既有基金的写法,评分语句用locals()注入的真实统计量
Scan to join WeChat group