skills/portfolio-analyzer/SKILL.md
wangyitong a65adcc2e5 Initial commit: merged, deduplicated, and vetted skill collection
Sources: extracted from two upstream archives (skill-repo, skills-main),
merged with the following policy:

- 15 broken symlinks (pointing to /Users/jameslee/.cc-switch/skills or
  ../../.agents/skills on a foreign machine) discarded
- 3 real name collisions with identical content (ai-pair, ifind-http-api,
  zhipu-websearch) kept as one copy
- Functional overlaps deduped keeping the strongest variant:
  - docx family: kept docx (official, full toolchain) + docx-cn
    (GB/T 9704 Chinese official-document constants),
    dropped docx_writer (no scripts, name collided with docx)
  - humanizer family: kept humanizer-zh (6 zh reference docs),
    dropped humanizer (en, redundant for CN workflow)
- Skills that only ran in a foreign environment removed:
  ablemind-ops, app-publish, hlb-design-system, openclaw-adj-skill,
  claude-driver
- alphapai excluded from this public repo because its SKILL.md hard-coded
  live credentials

Result: 25 skills, 572 files, ~7.5 MB.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 14:47:12 +08:00

11 KiB
Raw Permalink Blame History

name description
portfolio-analyzer 投资组合多维分析与 Excel 报告生成。当用户需要进行组合 vs 基准收益对比、 风险指标计算、行业归因分析Brinson 三因素)、资产大类归因, 或从组合 Excel 数据生成分析报告时触发。 关键词: 组合分析、业绩归因、行业归因、组合对比、净值分析、风险指标、 Brinson、夏普比率、最大回撤、信息比率

投资组合分析

触发条件

当用户需要:

  • 多组合 vs 基准的收益对比分析
  • 计算风险指标(夏普、最大回撤、信息比率、索提诺等)
  • 行业归因分析Brinson 三因素:配置 + 选股 + 交互)
  • 资产大类业绩归因
  • 从组合 Excel 数据生成分析报告
  • 分析净值曲线、回撤、滚动波动率

依赖

依赖 用途 必需
windpy-sdk 获取基准净值 + 申万行业收益 Wind 数据)
xlsx Excel 输出规范 + recalc.py 公式验证 是(报告输出)
plotly 净值曲线 + 归因柱状图的交互式 HTML 否(可选)

快速开始

import sys, os
sys.path.insert(0, os.path.expanduser("~/.claude/skills/portfolio-analyzer/scripts"))
from portfolio_analyzer import (
    load_portfolio_data,
    fetch_benchmark,
    fetch_benchmark_industry_weights,
    fetch_shenwan_returns,
    compute_risk_metrics,
    compute_brinson,
)

# 1. 加载用户 Excel
data = load_portfolio_data("/path/to/portfolio.xlsx")
nav = data["nav_timeseries"]          # 宽表: 列=组合, index=日期

# 2. 获取基准
bench = fetch_benchmark("000300.SH", "2025-01-01", "2026-02-27")

# 3. 计算风险指标
metrics = compute_risk_metrics(nav["P001"], bench["close"])

# 4. Brinson 行业归因
ind = data["industry_attribution"]
result = compute_brinson(
    ind["port_weight"], ind["bench_weight"],
    ind["port_return"], ind["bench_return"],
)

工作流

第 1 步:解析用户请求

从用户消息中提取:

  • 输入 Excel 路径(必需)
  • 分析区间:起止日期,默认取 Excel 数据全区间
  • 基准选择:默认沪深 300000300.SH用户可指定中证 500/800/1000 等
  • 组合筛选:分析全部组合或指定组合代码

常用基准代码:

基准 Wind 代码
沪深 300 000300.SH
中证 500 000905.SH
中证 800 000906.SH
中证 1000 000852.SH
上证 50 000016.SH
创业板指 399006.SZ
万得全 A 881001.WI

第 2 步:加载数据

data = load_portfolio_data(filepath)

自动识别 5 张表(通过特征列匹配,不依赖 sheet 名称):

表类型 键名 识别特征
时序分析 nav_timeseries 含"单位净值"/"NAV"列
交易明细 trade_detail 含"成交金额"/"买卖方向"列
收益贡献 return_contribution 含"收益贡献"/"收益率贡献"列
业绩归因 asset_attribution 含"资产大类"列
行业归因 industry_attribution 含"行业"+"配置效应"列

参考:列名映射规则见 references/data-loading-guide.md

第 3 步:获取基准数据

bench = fetch_benchmark("000300.SH", start, end)
# 返回 DataFrame: columns=["close"], index=DatetimeIndex

第 4 步:获取行业基准

# 4a. 基准指数的行业权重bw_i
bench_weights = fetch_benchmark_industry_weights("000300.SH", "20260227")
# 返回 Series: index=行业名称, values=权重(0~1)

# 4b. 各行业指数的区间收益br_i
sw = fetch_shenwan_returns(start, end)
# 返回 DataFrame: index=行业名称, columns=["code", "pct_chg"]

fetch_benchmark_industry_weights 内部流程:

  1. wset("indexconstituent") 拉取成分股及权重
  2. wss(codes, "industry_sw") 查每只股票的申万一级行业(分批,每批 80 只)
  3. 按行业聚合权重并归一化

参考31 个申万一级行业代码见 references/shenwan-industry-codes.md

第 5 步:收益分析

对每个组合计算:

  • 累计收益率:nav / nav.iloc[0] - 1
  • 日收益率:nav.pct_change()
  • 超额收益:组合累计 - 基准累计

第 6 步:风险分析

metrics = compute_risk_metrics(nav_series, benchmark_series, rf=0.015)

返回 8 个指标:

指标 含义 Excel 格式
年化收益率 复合年化回报 0.00%
年化波动率 收益率标准差年化 0.00%
最大回撤 峰谷最大跌幅 0.00%
夏普比率 单位风险超额收益 0.00
信息比率 单位跟踪误差超额 0.00
卡尔玛比率 年化收益/最大回撤 0.00
索提诺比率 单位下行风险超额 0.00
胜率 正收益天数占比 0.00%

参考:公式详情见 references/risk-metrics-formulas.md

辅助分析:

from portfolio_analyzer import rolling_volatility, drawdown_series, top_drawdowns

vol = rolling_volatility(nav_series, window=20)    # 20日滚动波动率
dd = drawdown_series(nav_series)                    # 每日回撤
top5 = top_drawdowns(nav_series, n=5)               # Top5 回撤

第 7 步行业归因Brinson 三因素)

result = compute_brinson(port_weights, bench_weights, port_returns, bench_returns)
# columns: ["配置效应", "选股效应", "交互效应", "总归因"]

数据来源优先级

  1. 若用户 Excel 已包含行业归因数据(表 5 有 port_weight/bench_weight/port_return/bench_return直接使用
  2. 否则从 Wind 构建全部 4 个输入:
    • pw_i 组合行业权重:从表 3 收益贡献按行业聚合 weight
    • bw_i 基准行业权重:fetch_benchmark_industry_weights("000300.SH", date)
    • pr_i 组合行业收益:从表 3 按行业聚合 sec_return(加权平均)
    • br_i 基准行业收益:fetch_shenwan_returns(start, end)["pct_chg"]

第 8 步:生成 Excel 报告

使用 openpyxl 生成 6 个 sheet 的 Excel 报告,遵循 xlsx skill 格式规范。

Sheet 1: 概览

多组合指标对比仪表盘:

       | 组合A    | 组合B    | 基准     |
年化收益 | 12.50%  | 8.30%   | 10.20%  |  ← 最优绿色
年化波动 | 15.20%  | 12.80%  | 14.50%  |  ← 最低绿色
最大回撤 | 18.50%  | 12.30%  | 15.80%  |  ← 最低绿色
夏普比率 | 0.72    | 0.53    | 0.60    |  ← 最高绿色

条件格式:每行最优值绿色底色,最差值红色底色。

Sheet 2: 净值曲线

内容 来源
A 日期 数据
B+ 各组合 NAV 数据
之后 基准 NAV Wind
之后 各组合日收益率 公式 =B3/B2-1
之后 各组合累计收益率 公式 =B3/B$2-1

冻结首行首列。

Sheet 3: 风险分析

  • 滚动波动率列(辅助列计算 20 日标准差)
  • 回撤序列(辅助列 RunningMax = MAX($B$2:B2)Drawdown = (RunMax-NAV)/RunMax
  • Top 5 最大回撤表(起始日、最低点、幅度)

Sheet 4: 收益归因

  • 资产大类归因表(从表 4 直接输出)
  • 个股贡献 Top 10 / Bottom 10从表 3 排序)
  • 条件格式:正值绿色,负值红色
  • SUM 校验行验证归因加总

Sheet 5: 行业归因

  • Brinson 配置/选股/交互效应
  • 按总归因降序排序
  • 数据条可视化(配置效应、选股效应列)
  • 底部合计行

Sheet 6: 交易明细

  • 原始交易数据透传
  • 自动筛选 + 冻结首行

第 9 步:公式验证

python ~/.claude/skills/xlsx/scripts/recalc.py output.xlsx
# 期望输出: 0 个公式错误

Excel 格式规范

遵循 xlsx skill 标准:

元素 规范
输入数据字体 蓝色 (0000FF)
公式字体 黑色 (000000)
百分比 0.00% 格式
负数 用括号 (0.00%)
表头 深蓝底白字,加粗
千分位 金额列用 #,##0
冻结窗格 所有 sheet 冻结首行

函数参考

load_portfolio_data(filepath) -> dict

解析组合 Excel 文件,自动识别 5 张表。

参数 类型 说明
filepath str Excel 文件路径
返回 dict 键为表类型,值为 DataFrame

fetch_benchmark(code, start, end) -> DataFrame

通过 Wind 获取基准指数收盘价。

参数 类型 说明
code str 指数代码,如 "000300.SH"
start str 起始日期
end str 结束日期
返回 DataFrame columns=["close"], index=日期

fetch_benchmark_industry_weights(index_code, date) -> Series

获取基准指数的申万一级行业权重分布。

参数 类型 说明
index_code str 指数代码,如 "000300.SH"
date str 日期,如 "20260227"
返回 Series index=行业名, values=权重(0~1)

内部调用 wset("indexconstituent") + wss(codes, "industry_sw") 分批查询后聚合。

fetch_shenwan_returns(start, end) -> DataFrame

获取 31 个申万一级行业区间涨跌幅。

参数 类型 说明
start str 起始日期
end str 结束日期
返回 DataFrame index=行业名, columns=["code","pct_chg"]

compute_risk_metrics(nav, benchmark, rf) -> dict

计算 8 个风险指标。

参数 类型 说明
nav Series 组合净值序列
benchmark Series 基准净值序列(可选)
rf float 无风险利率,默认 0.015
返回 dict 8 个指标名 → 数值

compute_brinson(pw, bw, pr, br) -> DataFrame

Brinson 三因素行业归因。

参数 类型 说明
pw Series 组合行业权重
bw Series 基准行业权重
pr Series 组合行业收益
br Series 基准行业收益
返回 DataFrame 配置/选股/交互/总归因,按总归因排序

辅助函数

函数 说明
align_nav(nav1, nav2) 按日期对齐两个净值序列
rolling_volatility(nav, window=20) 滚动年化波动率
drawdown_series(nav) 每日回撤幅度序列
top_drawdowns(nav, n=5) 提取前 N 次最大回撤
cumulative_return(nav) 累计收益率序列
daily_returns(nav) 日收益率序列
match_industry(name) 行业名称模糊匹配到 Wind 代码

常见场景

场景 1多组合月度绩效报告

用户: 帮我分析这个月组合的表现Excel 在 ~/data/portfolio_202602.xlsx
     基准用沪深300

→ 执行完整 9 步工作流,输出 6-sheet Excel 报告

场景 2单组合深度风险分析

用户: 分析组合 P001 的回撤和波动率

→ 只执行步骤 1-2-3-6重点输出风险分析 sheet滚动波动率 + Top5 回撤)

场景 3行业归因分析

用户: 帮我做 Brinson 行业归因Excel 里有行业权重和收益数据

→ 步骤 1-2-4-7重点输出行业归因 sheet

场景 4组合间横向对比

用户: 对比这 5 个组合的夏普比率和最大回撤

→ 步骤 1-2-3-5-6重点输出概览 sheet仪表盘