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>
686 lines
20 KiB
Markdown
686 lines
20 KiB
Markdown
# 金融研究报告撰写技能
|
||
|
||
## 概述
|
||
本技能用于协助用户撰写专业的A股上市公司投资研究报告,涵盖数据获取、分析和文档格式化等全流程。
|
||
|
||
## 适用场景
|
||
- 撰写上市公司周报、月报或专项研究报告
|
||
- 需要使用Wind金融终端获取实时或历史数据
|
||
- 生成符合中国国家标准的Word格式文档
|
||
- 技术分析与基本面分析相结合的投资报告
|
||
|
||
## 核心能力
|
||
|
||
### 1. 数据获取(WindPy SDK)
|
||
|
||
#### 连接Wind终端
|
||
```python
|
||
from WindPy import w
|
||
w.start()
|
||
data = w.wsd("300866.SZ", "close", "2025-11-01", "2026-02-06")
|
||
w.stop()
|
||
```
|
||
|
||
#### 常用数据函数
|
||
- `w.wsd()` - 日线序列数据
|
||
- `w.wsi()` - 分钟线数据
|
||
- `w.wss()` - 截面数据(最新值)
|
||
- `wsd` 常用字段:
|
||
- `close` - 收盘价
|
||
- `open`/`high`/`low` - 开盘/最高/最低价
|
||
- `volume`/`amt` - 成交量/成交额
|
||
- `pct_chg` - 涨跌幅
|
||
- `ma5`, `ma10`, `ma20`, `ma60` - 均线
|
||
- `roe` - 净资产收益率
|
||
- `pe_ttm`, `pb_lf` - 市盈率/市净率
|
||
|
||
#### 技术指标计算
|
||
- 移动平均线:MA5, MA10, MA20, MA60
|
||
- 波动率:使用标准差计算年化波动率
|
||
- 支撑位/阻力位:基于高低点分析
|
||
|
||
### 2. Word文档格式化(python-docx)
|
||
|
||
#### 国家标准 GB/T 9704-2012
|
||
|
||
**页面设置**
|
||
```python
|
||
from docx.shared import Mm
|
||
section.top_margin = Mm(37)
|
||
section.bottom_margin = Mm(35)
|
||
section.left_margin = Mm(28)
|
||
section.right_margin = Mm(26)
|
||
```
|
||
|
||
**字体规范**
|
||
```python
|
||
def set_font(run, font_name, size=None, bold=None):
|
||
run.font.name = font_name
|
||
run.font.size = Pt(size) if size else None
|
||
if bold is not None:
|
||
run.font.bold = bold
|
||
# 设置中文字体
|
||
run._element.rPr.rFonts.set(qn('w:eastAsia'), font_name)
|
||
|
||
# 三号标题:16pt
|
||
# 四号正文:14pt
|
||
# 小四表格:12pt
|
||
```
|
||
|
||
**字号对照表**
|
||
- 三号:16pt
|
||
- 四号:14pt
|
||
- 小四:12pt
|
||
- 五号:10.5pt
|
||
|
||
**行距设置**
|
||
```python
|
||
paragraph.paragraph_format.line_spacing = Pt(28) # 正文
|
||
paragraph.paragraph_format.line_spacing = Pt(25) # 小标题
|
||
paragraph.paragraph_format.line_spacing_rule = 2 # 固定值
|
||
```
|
||
|
||
**段落格式**
|
||
```python
|
||
# 首行缩进2字符(28pt)
|
||
paragraph.paragraph_format.first_line_indent = Pt(28)
|
||
|
||
# 两端对齐
|
||
paragraph.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY
|
||
|
||
# 段前段后距
|
||
paragraph.paragraph_format.space_before = Pt(0)
|
||
paragraph.paragraph_format.space_after = Pt(0)
|
||
```
|
||
|
||
#### 三线表格式
|
||
|
||
```python
|
||
def set_table_borders(table):
|
||
tblPr = table._tbl.tblPr
|
||
tblBorders = OxmlElement('w:tblBorders')
|
||
# 顶底边框 1.5pt (sz=18)
|
||
for pos in ['top', 'bottom']:
|
||
border = OxmlElement(f'w:{pos}')
|
||
border.set(qn('w:val'), 'single')
|
||
border.set(qn('w:sz'), '18')
|
||
border.set(qn('w:color'), 'auto')
|
||
tblBorders.append(border)
|
||
# 内部横线 0.75pt (sz=9)
|
||
for pos in ['insideH']:
|
||
border = OxmlElement(f'w:{pos}')
|
||
border.set(qn('w:val'), 'single')
|
||
border.set(qn('w:sz'), '9')
|
||
border.set(qn('w:color'), 'auto')
|
||
tblBorders.append(border)
|
||
# 无左右和竖线
|
||
for pos in ['left', 'right', 'insideV']:
|
||
border = OxmlElement(f'w:{pos}')
|
||
border.set(qn('w:val'), 'none')
|
||
tblBorders.append(border)
|
||
tblPr.append(tblBorders)
|
||
```
|
||
|
||
#### 页脚页码
|
||
```python
|
||
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
||
footer = section.footer
|
||
p = footer.paragraphs[0] if footer.paragraphs else footer.add_paragraph()
|
||
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||
r1 = p.add_run('—')
|
||
set_font(r1, '仿宋', 12)
|
||
r2 = p.add_run() # 页码占位
|
||
set_font(r2, '仿宋', 12)
|
||
r3 = p.add_run(' ')
|
||
set_font(r3, '仿宋', 12)
|
||
r4 = p.add_run() # 页码占位
|
||
set_font(r4, '仿宋', 12)
|
||
r5 = p.add_run('—')
|
||
set_font(r5, '仿宋', 12)
|
||
```
|
||
|
||
### 3. 报告结构标准
|
||
|
||
#### 完整报告结构(可选封面版)
|
||
1. **封面页**
|
||
- 标题:黑体三号(16pt),居中
|
||
- 报告机构和日期:黑体三号(16pt),居中
|
||
|
||
2. **免责声明**(可选)
|
||
- 标题:黑体三号(16pt),居中
|
||
- 内容:仿宋四号(14pt),两端对齐
|
||
|
||
3. **核心提要**
|
||
- 标题:黑体三号(16pt),居中
|
||
- 内容:3-4个要点,仿宋四号(14pt),首行缩进2字符
|
||
|
||
4. **一、投资评级**
|
||
- 标题:黑体三号(16pt)
|
||
- 评级表格:小四(12pt),三线表
|
||
- 内容:投资建议、目标价格、有效期、风险等级
|
||
|
||
5. **二、核心观点**
|
||
- 标题:黑体三号(16pt)
|
||
- 内容:基本面+技术面分析+投资建议
|
||
|
||
6. **三、市场表现回顾**
|
||
- 标题:黑体三号(16pt)
|
||
- (一)价格走势分析:黑体三号(16pt)
|
||
- (二)K线数据表:标题黑体小四(12pt)
|
||
|
||
#### 简化报告结构(无封面)
|
||
- 核心提要 → 一、投资评级 → 二、核心观点 → 三、市场表现回顾
|
||
- 不使用分页符,保持内容连贯
|
||
|
||
### 4. 内容撰写要点
|
||
|
||
#### 核心提要
|
||
- 突出关键数据(ROE、涨跌幅等)
|
||
- 简明扼要,3-4个要点
|
||
- 包含明确的投资建议
|
||
|
||
#### 核心观点
|
||
- 基本面:盈利能力(ROE)、估值水平(PE/PB)
|
||
- 技术面:价格趋势、均线、支撑阻力位
|
||
- 投资建议:具体操作策略
|
||
|
||
#### 市场表现回顾
|
||
- 时间周期:近13周(周线数据)
|
||
- 价格区间:最高价、最低价、累计涨跌幅
|
||
- 数据表格:日期、开盘、最高、最低、收盘、涨跌幅、成交量
|
||
|
||
### 5. 数据处理技巧
|
||
|
||
#### 时间序列对齐
|
||
```python
|
||
import pandas as pd
|
||
df = pd.DataFrame(data, columns=['date', 'open', 'high', 'low', 'close'])
|
||
df['date'] = pd.to_datetime(df['date'])
|
||
df.sort_values('date', ascending=True)
|
||
```
|
||
|
||
#### 周线数据汇总
|
||
```python
|
||
df_weekly = df.resample('W').agg({
|
||
'open': 'first',
|
||
'high': 'max',
|
||
'low': 'min',
|
||
'close': 'last',
|
||
'volume': 'sum'
|
||
})
|
||
```
|
||
|
||
#### 波动率计算
|
||
```python
|
||
import numpy as np
|
||
returns = df['close'].pct_change().dropna()
|
||
volatility = returns.std() * np.sqrt(52) * 100 # 年化百分比
|
||
```
|
||
|
||
### 6. 常见问题解决
|
||
|
||
#### 字体显示问题
|
||
- 必须同时设置中文字体:`run._element.rPr.rFonts.set(qn('w:eastAsia'), font_name)`
|
||
- 不要只设置 `run.font.name`
|
||
|
||
#### 表格单元格格式
|
||
- Cell对象没有 `paragraph_format` 属性
|
||
- 需要通过 `cell.paragraphs[0].paragraph_format` 访问
|
||
|
||
#### Run对象访问
|
||
- Run对象没有 `runs` 属性
|
||
- 段落的runs通过 `paragraph.runs` 访问
|
||
|
||
#### 行距单位
|
||
- 使用 `Pt()` 设置固定行距(点)
|
||
- `line_spacing_rule = 2` 表示固定值
|
||
|
||
## 使用示例
|
||
|
||
### 基本流程
|
||
1. 使用WindPy SDK获取股票数据
|
||
2. 计算技术指标(MA、波动率等)
|
||
3. 分析基本面指标(ROE、PE等)
|
||
4. 整理分析结论
|
||
5. 使用python-docx生成Word文档
|
||
6. 应用GB/T 9704-2012格式规范
|
||
7. 保存文档
|
||
|
||
### 快速检查清单(Word文档)
|
||
- [ ] 页面边距:37/35/28/26mm
|
||
- [ ] 字体:标题黑体三号、正文仿宋四号、表格小四
|
||
- [ ] 行距:正文28pt、小标题25pt
|
||
- [ ] 首行缩进:正文2字符(28pt)
|
||
- [ ] 三线表:顶底1.5pt、内部0.75pt、无边框
|
||
- [ ] 数据来源注脚:右对齐,小四(12pt)
|
||
|
||
### Excel图表检查清单
|
||
详见「图表设置检查清单」表格(第7节末尾)
|
||
|
||
## 注意事项
|
||
|
||
1. **字体重要性**:中文文本必须设置 `w:eastAsia` 属性,否则可能显示为默认字体
|
||
2. **表格边框**:使用三线表格式,无左右和竖线
|
||
3. **段落缩进**:正文段落需要首行缩进,标题不需要
|
||
4. **分页控制**:根据需要决定是否分页,简化版通常不分页
|
||
5. **数据时效**:注意数据更新日期,避免使用过期数据
|
||
6. **投资建议**:提供明确的操作策略,但需提醒风险
|
||
|
||
### 7. Excel 图表绘制(openpyxl)
|
||
|
||
本技能支持生成包含原生 Excel 图表的 .xlsx 文件,图表可在 Excel 中编辑和交互。
|
||
|
||
#### 基础图表创建
|
||
|
||
```python
|
||
from openpyxl import Workbook
|
||
from openpyxl.chart import LineChart, BarChart, Reference
|
||
from openpyxl.chart.axis import DateAxis
|
||
|
||
# 创建工作簿
|
||
wb = Workbook()
|
||
ws = wb.active
|
||
ws.title = "股价走势"
|
||
|
||
# 写入数据
|
||
ws.append(["日期", "收盘价", "成交量"])
|
||
for date, close, vol in data:
|
||
ws.append([date, close, vol])
|
||
|
||
# 创建折线图(股价走势)
|
||
chart = LineChart()
|
||
chart.title = "股价走势"
|
||
chart.y_axis.title = "价格(元)"
|
||
chart.x_axis.title = "日期"
|
||
|
||
# 设置数据区域
|
||
data_ref = Reference(ws, min_col=2, min_row=1, max_row=len(data)+1)
|
||
cats_ref = Reference(ws, min_col=1, min_row=2, max_row=len(data)+1)
|
||
chart.add_data(data_ref, titles_from_data=True)
|
||
chart.set_categories(cats_ref)
|
||
|
||
# 设置样式
|
||
chart.style = 10
|
||
chart.height = 10 # 高度(厘米)
|
||
chart.width = 20 # 宽度(厘米)
|
||
|
||
# 添加到工作表
|
||
ws.add_chart(chart, "D2")
|
||
wb.save("股价走势.xlsx")
|
||
```
|
||
|
||
#### 常用图表类型
|
||
|
||
**折线图(LineChart)**
|
||
- 适用:股价走势、均线趋势
|
||
- 特点:展示时间序列变化
|
||
|
||
```python
|
||
from openpyxl.chart import LineChart
|
||
chart = LineChart()
|
||
chart.add_data(data_ref)
|
||
chart.set_categories(cats_ref)
|
||
```
|
||
|
||
**柱状图(BarChart)**
|
||
- 适用:成交量对比、财务数据对比
|
||
- 特点:横向展示数据大小
|
||
|
||
```python
|
||
from openpyxl.chart import BarChart
|
||
chart = BarChart()
|
||
chart.type = "col" # 垂直柱状图
|
||
chart.add_data(data_ref)
|
||
```
|
||
|
||
**组合图表(股价+成交量)**
|
||
- 适用:K线+成交量组合展示
|
||
- 特点:双Y轴,价格+量能
|
||
|
||
```python
|
||
from openpyxl.chart import LineChart, BarChart
|
||
from openpyxl.chart.series import DataPoint
|
||
|
||
# 主图:股价线
|
||
price_chart = LineChart()
|
||
price_chart.add_data(price_ref, titles_from_data=True)
|
||
price_chart.y_axis.title = "价格(元)"
|
||
|
||
# 副图:成交量柱状
|
||
vol_chart = BarChart()
|
||
vol_chart.add_data(vol_ref, titles_from_data=True)
|
||
vol_chart.y_axis.axId = 200 # 设置次要Y轴
|
||
vol_chart.y_axis.title = "成交量(手)"
|
||
|
||
# 组合图表
|
||
price_chart += vol_chart
|
||
price_chart.y_axis.crosses = "max" # 成交量轴在右侧
|
||
```
|
||
|
||
#### 图表样式设置
|
||
|
||
**线条与颜色规范**
|
||
```python
|
||
# 线条样式
|
||
from openpyxl.chart.series import DataPoint
|
||
from openpyxl.drawing.fill import SolidColorFillProperties
|
||
from openpyxl.drawing.line import LineProperties
|
||
|
||
series = chart.series[0]
|
||
series.graphicalProperties.line.solidFill = "4472C4" # 线条颜色
|
||
series.graphicalProperties.line.width = 25000 # 线条粗细(EMUs)
|
||
|
||
# 标记点样式
|
||
series.marker.symbol = "circle"
|
||
series.marker.size = 5
|
||
```
|
||
|
||
**A股颜色规范(涨跌自动着色)**
|
||
```python
|
||
# 柱状图根据涨跌自动设置颜色(红涨绿跌)
|
||
from openpyxl.drawing.fill import PatternFillProperties, ColorChoice
|
||
from openpyxl.chart.series import DataPoint
|
||
|
||
# 为每个数据点设置颜色
|
||
for i, val in enumerate(values):
|
||
pt = DataPoint(idx=i)
|
||
# A股规范:上涨红色,下跌绿色
|
||
fill_color = "FF0000" if val >= 0 else "00B050"
|
||
pt.graphicalProperties = GraphicalProperties(
|
||
solidFill=fill_color
|
||
)
|
||
series.data_points.append(pt)
|
||
```
|
||
|
||
**网格线与图例**
|
||
```python
|
||
# 网格线设置(研报风格:仅水平主网格线)
|
||
chart.x_axis.majorGridlines = None # 隐藏X轴网格
|
||
chart.y_axis.majorGridlines = None # 或设置为浅灰色虚线
|
||
|
||
# 图例位置
|
||
chart.legend.position = "b" # 底部:b, 右侧:r, 顶部:t, 左侧:l
|
||
```
|
||
|
||
#### 双轴图表(价格+涨跌幅)
|
||
|
||
```python
|
||
from openpyxl.chart import LineChart
|
||
from openpyxl.chart.axis import DateAxis
|
||
|
||
# 主图:股价
|
||
price_chart = LineChart()
|
||
price_chart.add_data(price_ref, titles_from_data=True)
|
||
price_chart.y_axis.title = "价格(元)"
|
||
|
||
# 副图:涨跌幅(柱状)
|
||
pct_chart = LineChart()
|
||
pct_chart.add_data(pct_ref, titles_from_data=True)
|
||
pct_chart.y_axis.axId = 200
|
||
pct_chart.y_axis.title = "涨跌幅(%)"
|
||
|
||
# 组合
|
||
price_chart += pct_chart
|
||
price_chart.y_axis.crosses = "max"
|
||
```
|
||
|
||
#### 坐标轴精修(研报级设置)
|
||
|
||
**数值轴(Y轴)刻度设置**
|
||
```python
|
||
# 设置Y轴最大最小值(避免自动刻度导致的空白过多)
|
||
chart.y_axis.scaling.min = 10 # 根据实际数据调整
|
||
chart.y_axis.scaling.max = 50
|
||
|
||
# 设置主要刻度单位
|
||
chart.y_axis.majorUnit = 5
|
||
|
||
# 对于大数值(如成交量),建议数据预处理转换为"亿"或"万"
|
||
# 并在轴标题中注明单位
|
||
chart.y_axis.title = "成交量(亿元)"
|
||
```
|
||
|
||
**日期轴(X轴)标签优化**
|
||
```python
|
||
from openpyxl.chart.axis import DateAxis
|
||
from openpyxl.drawing.text import Paragraph, ParagraphProperties, CharacterProperties
|
||
|
||
# 设置X轴为日期轴
|
||
chart.x_axis = DateAxis()
|
||
chart.x_axis.title = "日期"
|
||
|
||
# 标签间隔(避免数据点过多导致重叠)
|
||
chart.x_axis.tickLblSkip = 5 # 每5个数据点显示一个标签
|
||
|
||
# 标签旋转(防止重叠)
|
||
from copy import deepcopy
|
||
from openpyxl.drawing.text import RichText
|
||
rt = RichText(p=[Paragraph(
|
||
pPr=ParagraphProperties(defRPr=CharacterProperties(sz=900)),
|
||
endParaRPr=CharacterProperties(sz=900)
|
||
)])
|
||
chart.x_axis.txPr = rt
|
||
```
|
||
|
||
**坐标轴数字格式**
|
||
```python
|
||
# Y轴数字格式(保留2位小数)
|
||
chart.y_axis.numFmt = '0.00'
|
||
|
||
# 百分比格式
|
||
chart.y_axis.numFmt = '0.00%'
|
||
```
|
||
|
||
#### 数据标签与参考线(视觉增强)
|
||
|
||
**数据标签设置**
|
||
```python
|
||
from openpyxl.chart.label import DataLabelList
|
||
|
||
# 显示所有数据点的值
|
||
chart.dataLabels = DataLabelList()
|
||
chart.dataLabels.showVal = True
|
||
|
||
# 仅显示最后一个点(标注最新价)- 需要手动设置
|
||
from openpyxl.chart.series import DataPoint
|
||
last_pt = DataPoint(idx=len(values)-1)
|
||
last_pt.graphicalProperties = GraphicalProperties(solidFill="FF0000")
|
||
series.data_points = [last_pt]
|
||
```
|
||
|
||
**参考线(均值/目标价)**
|
||
```python
|
||
from openpyxl.chart.series import SeriesLabel
|
||
|
||
# 添加均值参考线(作为单独的数据系列)
|
||
mean_value = sum(values) / len(values)
|
||
ws.append([""] * (len(headers)-1) + ["均值"])
|
||
for i in range(len(values)):
|
||
ws.append([""] * (len(headers)-1) + [mean_value])
|
||
|
||
mean_ref = Reference(ws, min_col=len(headers), min_row=len(values)+2, max_row=len(values)*2+1)
|
||
mean_series = Series(mean_ref, title="均值线")
|
||
chart.series.append(mean_series)
|
||
```
|
||
|
||
#### 财务数据可视化
|
||
|
||
**营收利润趋势图**
|
||
```python
|
||
# 数据准备
|
||
ws.append(["报告期", "营业收入", "净利润"])
|
||
for period, revenue, profit in financial_data:
|
||
ws.append([period, revenue/1e8, profit/1e8]) # 转换为亿元
|
||
|
||
# 组合图表
|
||
chart = BarChart()
|
||
chart.type = "col"
|
||
chart.grouping = "clustered"
|
||
chart.title = "营业收入与净利润"
|
||
chart.y_axis.title = "金额(亿元)"
|
||
|
||
data = Reference(ws, min_col=2, max_col=3, min_row=1, max_row=len(financial_data)+1)
|
||
cats = Reference(ws, min_col=1, min_row=2, max_row=len(financial_data)+1)
|
||
chart.add_data(data, titles_from_data=True)
|
||
chart.set_categories(cats)
|
||
|
||
# 添加数据标签
|
||
chart.dataLabels = DataLabelList()
|
||
chart.dataLabels.showVal = True
|
||
```
|
||
|
||
**ROE 柱状图**
|
||
```python
|
||
chart = BarChart()
|
||
chart.type = "col"
|
||
data = Reference(ws, min_col=2, min_row=1, max_row=5)
|
||
cats = Reference(ws, min_col=1, min_row=2, max_row=5)
|
||
chart.add_data(data, titles_from_data=True)
|
||
chart.set_categories(cats)
|
||
chart.title = "年度 ROE 对比"
|
||
```
|
||
|
||
#### Excel 文件与 Word 报告配合
|
||
|
||
**方案A:Excel 作为附件**
|
||
```python
|
||
# 生成带图表的 Excel 文件
|
||
wb.save(f"{stock_name}_数据分析.xlsx")
|
||
|
||
# 在 Word 中引用
|
||
paragraph = doc.add_paragraph()
|
||
run = paragraph.add_run(f"详细数据及图表请参见附件《{stock_name}_数据分析.xlsx》")
|
||
set_font(run, "仿宋", 12)
|
||
```
|
||
|
||
**方案B:图表图片直接插入 Word(推荐)**
|
||
```python
|
||
import matplotlib.pyplot as plt
|
||
import matplotlib.dates as mdates
|
||
from docx.shared import Inches
|
||
|
||
# 使用 Matplotlib 生成符合 GB/T 9704 字体要求的图表
|
||
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']
|
||
plt.rcParams['axes.unicode_minus'] = False
|
||
|
||
fig, ax = plt.subplots(figsize=(8, 4.5))
|
||
ax.plot(dates, prices, color='#4472C4', linewidth=1.5)
|
||
ax.set_title('股价走势', fontsize=12, fontweight='bold')
|
||
ax.set_xlabel('日期', fontsize=10)
|
||
ax.set_ylabel('价格(元)', fontsize=10)
|
||
ax.grid(True, alpha=0.3)
|
||
|
||
# 保存为图片
|
||
fig.savefig('chart.png', dpi=150, bbox_inches='tight')
|
||
plt.close()
|
||
|
||
# 插入 Word
|
||
doc.add_picture('chart.png', width=Inches(6))
|
||
```
|
||
|
||
**方案C:Word 原生图表(功能有限)**
|
||
```python
|
||
from docx.chart import Chart
|
||
from docx.enum.chart import XL_CHART_TYPE
|
||
|
||
# 注意:docx.chart 功能较弱,仅支持基础图表类型
|
||
# 如需复杂图表,建议使用方案A或B
|
||
```
|
||
|
||
#### 图表最佳实践
|
||
|
||
1. **数据准备**:使用 pandas 预处理数据,确保格式正确
|
||
2. **图表选择**:
|
||
- 时间序列 → 折线图
|
||
- 对比分析 → 柱状图
|
||
- 价格+成交量 → 组合图
|
||
3. **颜色规范**(A股标准):
|
||
- 上涨:红色(FF0000)
|
||
- 下跌:绿色(00B050,推荐)或(00AA00)
|
||
- 中性:蓝色(4472C4)
|
||
4. **数据单位**:图表标题或轴标题中注明单位(元、%、亿元等)
|
||
5. **数据来源**:图表下方注明数据来源,如"数据来源:Wind"
|
||
|
||
#### 图表设置检查清单
|
||
|
||
| 检查项 | 专业要求 | 常见错误 |
|
||
|--------|----------|----------|
|
||
| **坐标轴标题** | 必须包含单位,如"价格(元)"、"比例(%)" | 漏写单位或单位不统一 |
|
||
| **色彩方案** | 涨红跌绿(A股规范),多序列使用高对比度商务色 | 使用 Excel 默认全家桶配色 |
|
||
| **网格线** | 仅保留水平主网格线,且设为浅灰色/虚线,或直接隐藏 | 粗黑实线网格,遮盖趋势线 |
|
||
| **字体统一** | 图表内字体需与 Word 正文匹配(建议微软雅黑或等线,9pt) | 默认小号宋体,缩放后模糊 |
|
||
| **数据源标注** | 图表下方须注明:数据来源:Wind,XX证券研究所 | 来源不明 |
|
||
| **标签间隔** | X轴数据点密集时需设置 `tickLblSkip` 防止重叠 | 标签重叠难以辨认 |
|
||
| **数值精度** | Y轴根据数据类型设置合适的小数位(价格2位,百分比1-2位) | 小数位过多或过少 |
|
||
|
||
#### 高度封装工具函数
|
||
|
||
工具函数已封装在 `scripts/chart_utils.py` 中,使用时直接导入:
|
||
|
||
```python
|
||
import sys
|
||
sys.path.insert(0, ".claude/skills/financial-report-writing/scripts")
|
||
from chart_utils import create_research_chart, create_price_volume_chart
|
||
|
||
import pandas as pd
|
||
|
||
# 准备数据
|
||
df = pd.DataFrame({
|
||
"date": ["2024-01", "2024-02", "2024-03"],
|
||
"close": [10.5, 11.2, 10.8]
|
||
})
|
||
|
||
# 生成股价走势图
|
||
wb = create_research_chart(
|
||
df,
|
||
chart_type="line",
|
||
title="股价走势",
|
||
x_col="date",
|
||
y_cols="close",
|
||
y_axis_title="价格(元)",
|
||
show_last_label_only=True,
|
||
add_mean_line=True,
|
||
output_path="股价走势.xlsx"
|
||
)
|
||
```
|
||
|
||
**可用函数**
|
||
|
||
| 函数 | 用途 |
|
||
|------|------|
|
||
| `create_research_chart()` | 通用图表(折线/柱状/多序列) |
|
||
| `create_price_volume_chart()` | 股价+成交量双Y轴组合图 |
|
||
|
||
**`create_research_chart()` 主要参数**
|
||
|
||
| 参数 | 说明 | 默认值 |
|
||
|------|------|--------|
|
||
| `df` | DataFrame数据源 | 必填 |
|
||
| `chart_type` | 图表类型:"line"/"bar" | "line" |
|
||
| `x_col` | X轴列名 | 必填 |
|
||
| `y_cols` | Y轴列名(支持列表) | 必填 |
|
||
| `y_axis_title` | Y轴标题(建议带单位) | "" |
|
||
| `y_format` | 数字格式 | "0.00" |
|
||
| `show_last_label_only` | 仅显示最后一个标签 | False |
|
||
| `add_mean_line` | 添加均值参考线 | False |
|
||
| `color_up/color_down` | 涨跌颜色 | FF0000/00B050 |
|
||
| `tick_skip` | X轴标签间隔 | 5 |
|
||
|
||
完整函数定义和源码见:`scripts/chart_utils.py`
|
||
|
||
## 相关工具
|
||
|
||
- **WindPy**:Wind金融终端Python API
|
||
- **python-docx**:Word文档操作库
|
||
- **openpyxl**:Excel文件操作,支持原生图表
|
||
- **pandas**:数据处理和分析
|
||
- **numpy**:数值计算
|
||
- **GB/T 9704-2012**:党政机关公文格式标准
|
||
|
||
## 参考资源
|
||
|
||
- WindPy SDK官方文档
|
||
- python-docx API文档
|
||
- GB/T 9704-2012国家公文格式标准
|
||
- 券商研究报告格式规范
|