# 金融研究报告撰写技能

## 概述
本技能用于协助用户撰写专业的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国家公文格式标准
- 券商研究报告格式规范
