Skip to content

Commit dd3e478

Browse files
suan babyclaude
andcommitted
fix: optimize financial data display format
1. Add table format for financial report and dividend metrics 2. Format large numbers with Chinese units (亿/千万/万/千) 3. Add percentage sign to ROE 4. Add yuan unit to cash dividend 5. Add times unit to dividend count Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 0a4bc2d commit dd3e478

1 file changed

Lines changed: 132 additions & 28 deletions

File tree

src/notification.py

Lines changed: 132 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,61 @@
6969
from src.analyzer import AnalysisResult
7070

7171

72+
def _format_large_number(value: Any) -> str:
73+
"""
74+
格式化大数字为亿/千万/万/千单位
75+
76+
Args:
77+
value: 数值或数字字符串
78+
79+
Returns:
80+
格式化后的字符串,如 "547.29亿" 或 "106.39元"
81+
"""
82+
if value is None or value == '':
83+
return 'N/A'
84+
85+
try:
86+
# 尝试转换为浮点数
87+
num = float(value)
88+
except (ValueError, TypeError):
89+
return str(value) if value else 'N/A'
90+
91+
# 处理负数
92+
prefix = "-" if num < 0 else ""
93+
abs_num = abs(num)
94+
95+
if abs_num >= 1_0000_0000: # >= 1亿
96+
return f"{prefix}{abs_num / 1_0000_0000:.2f}亿"
97+
elif abs_num >= 1_0000_000: # >= 1000万
98+
return f"{prefix}{abs_num / 1_0000_000:.2f}千万"
99+
elif abs_num >= 1_0000: # >= 1万
100+
return f"{prefix}{abs_num / 1_0000:.2f}万"
101+
elif abs_num >= 1000: # >= 1000
102+
return f"{prefix}{abs_num / 1000:.2f}千"
103+
else:
104+
return f"{prefix}{abs_num:.2f}"
105+
106+
107+
def _format_percentage(value: Any) -> str:
108+
"""
109+
格式化百分比值
110+
111+
Args:
112+
value: 百分比数值或字符串
113+
114+
Returns:
115+
格式化后的百分比字符串,如 "10.57%"
116+
"""
117+
if value is None or value == '':
118+
return 'N/A'
119+
120+
try:
121+
num = float(value)
122+
return f"{num:.2f}%"
123+
except (ValueError, TypeError):
124+
return str(value) if value else 'N/A'
125+
126+
72127
class NotificationChannel(Enum):
73128
"""通知渠道类型"""
74129
WECHAT = "wechat" # 企业微信
@@ -1023,28 +1078,51 @@ def generate_dashboard_report(
10231078
f"### 💰 {labels.get('financial_report_heading', '财务与分红')}",
10241079
"",
10251080
])
1026-
# 财务报告
1081+
# 财务报告 - 使用表格展示
10271082
if financial_report and isinstance(financial_report, dict):
10281083
report_lines.extend([
10291084
f"**📊 {labels.get('financial_report_label', '财务报告')}**",
10301085
"",
1031-
f"| {labels.get('report_period_label', '报告期')} | {financial_report.get('report_date', 'N/A')} |",
1032-
f"| {labels.get('revenue_label', '营业收入')} | {financial_report.get('revenue', 'N/A')} |",
1033-
f"| {labels.get('net_profit_label', '归母净利润')} | {financial_report.get('net_profit_parent', 'N/A')} |",
1034-
f"| {labels.get('roe_label', 'ROE')} | {financial_report.get('roe', 'N/A')} |",
1086+
f"| 指标 | 数值 |",
1087+
f"| --- | --- |",
1088+
f"| 报告期 | {financial_report.get('report_date', 'N/A')} |",
1089+
f"| 营业收入 | {_format_large_number(financial_report.get('revenue'))} |",
1090+
f"| 归母净利润 | {_format_large_number(financial_report.get('net_profit_parent'))} |",
1091+
f"| ROE | {_format_percentage(financial_report.get('roe'))} |",
10351092
"",
10361093
])
1037-
# 分红指标
1094+
# 分红指标 - 使用表格展示
10381095
if dividend_metrics and isinstance(dividend_metrics, dict):
1039-
ttm_yield = dividend_metrics.get('ttm_dividend_yield_pct', 'N/A')
1040-
ttm_cash = dividend_metrics.get('ttm_cash_dividend_per_share', 'N/A')
1096+
ttm_yield_raw = dividend_metrics.get('ttm_dividend_yield_pct')
1097+
ttm_cash_raw = dividend_metrics.get('ttm_cash_dividend_per_share')
10411098
ttm_count = dividend_metrics.get('ttm_event_count', 'N/A')
1099+
1100+
# 格式化股息率
1101+
if ttm_yield_raw is not None:
1102+
try:
1103+
ttm_yield = f"{float(ttm_yield_raw):.2f}%"
1104+
except (ValueError, TypeError):
1105+
ttm_yield = str(ttm_yield_raw)
1106+
else:
1107+
ttm_yield = 'N/A'
1108+
1109+
# 格式化每股分红(添加"元"单位)
1110+
if ttm_cash_raw is not None:
1111+
try:
1112+
ttm_cash = f"{float(ttm_cash_raw):.2f}元"
1113+
except (ValueError, TypeError):
1114+
ttm_cash = str(ttm_cash_raw)
1115+
else:
1116+
ttm_cash = 'N/A'
1117+
10421118
report_lines.extend([
10431119
f"**💵 {labels.get('dividend_label', '分红指标')}**",
10441120
"",
1045-
f"| {labels.get('ttm_yield_label', 'TTM股息率')} | {ttm_yield} |",
1046-
f"| {labels.get('ttm_cash_label', 'TTM每股现金分红')} | {ttm_cash} |",
1047-
f"| {labels.get('ttm_count_label', 'TTM分红次数')} | {ttm_count} |",
1121+
f"| 指标 | 数值 |",
1122+
f"| --- | --- |",
1123+
f"| TTM股息率 | {ttm_yield} |",
1124+
f"| TTM每股现金分红 | {ttm_cash} |",
1125+
f"| TTM分红次数 | {ttm_count} 次 |",
10481126
"",
10491127
])
10501128

@@ -1456,28 +1534,54 @@ def generate_wechat_dashboard(self, results: List[AnalysisResult]) -> str:
14561534
dividend_metrics = intel.get('dividend_metrics', {}) if intel else {}
14571535
if financial_report or dividend_metrics:
14581536
fin_lines = []
1537+
# 财务报告 - 使用表格展示
14591538
if financial_report and isinstance(financial_report, dict):
1460-
revenue = financial_report.get('revenue', '')
1461-
net_profit = financial_report.get('net_profit_parent', '')
1462-
roe = financial_report.get('roe', '')
1539+
revenue = financial_report.get('revenue')
1540+
net_profit = financial_report.get('net_profit_parent')
1541+
roe = financial_report.get('roe')
14631542
if any([revenue, net_profit, roe]):
14641543
fin_lines.append("### 💰 财务数据")
1465-
if revenue:
1466-
fin_lines.append(f"营收: {revenue}")
1467-
if net_profit:
1468-
fin_lines.append(f"净利润: {net_profit}")
1469-
if roe:
1470-
fin_lines.append(f"ROE: {roe}")
1471-
1544+
fin_lines.append("")
1545+
fin_lines.append("| 指标 | 数值 |")
1546+
fin_lines.append("| --- | --- |")
1547+
fin_lines.append(f"| 报告期 | {financial_report.get('report_date', 'N/A')} |")
1548+
fin_lines.append(f"| 营业收入 | {_format_large_number(revenue)} |")
1549+
fin_lines.append(f"| 归母净利润 | {_format_large_number(net_profit)} |")
1550+
fin_lines.append(f"| ROE | {_format_percentage(roe)} |")
1551+
1552+
# 分红指标 - 使用表格展示
14721553
if dividend_metrics and isinstance(dividend_metrics, dict):
1473-
ttm_yield = dividend_metrics.get('ttm_dividend_yield_pct')
1474-
ttm_cash = dividend_metrics.get('ttm_cash_dividend_per_share')
1475-
if ttm_yield or ttm_cash:
1554+
ttm_yield_raw = dividend_metrics.get('ttm_dividend_yield_pct')
1555+
ttm_cash_raw = dividend_metrics.get('ttm_cash_dividend_per_share')
1556+
ttm_count = dividend_metrics.get('ttm_event_count')
1557+
if ttm_yield_raw or ttm_cash_raw or ttm_count:
1558+
fin_lines.append("")
14761559
fin_lines.append("### 💵 分红指标")
1477-
if ttm_yield:
1478-
fin_lines.append(f"股息率: {ttm_yield}%")
1479-
if ttm_cash:
1480-
fin_lines.append(f"每股分红: {ttm_cash}元")
1560+
fin_lines.append("")
1561+
fin_lines.append("| 指标 | 数值 |")
1562+
fin_lines.append("| --- | --- |")
1563+
1564+
# 格式化股息率
1565+
if ttm_yield_raw is not None:
1566+
try:
1567+
ttm_yield = f"{float(ttm_yield_raw):.2f}%"
1568+
except (ValueError, TypeError):
1569+
ttm_yield = str(ttm_yield_raw)
1570+
else:
1571+
ttm_yield = 'N/A'
1572+
1573+
# 格式化每股分红
1574+
if ttm_cash_raw is not None:
1575+
try:
1576+
ttm_cash = f"{float(ttm_cash_raw):.2f}元"
1577+
except (ValueError, TypeError):
1578+
ttm_cash = str(ttm_cash_raw)
1579+
else:
1580+
ttm_cash = 'N/A'
1581+
1582+
fin_lines.append(f"| TTM股息率 | {ttm_yield} |")
1583+
fin_lines.append(f"| TTM每股分红 | {ttm_cash} |")
1584+
fin_lines.append(f"| TTM分红次数 | {ttm_count if ttm_count else 'N/A'} 次 |")
14811585

14821586
if fin_lines:
14831587
lines.extend(fin_lines)

0 commit comments

Comments
 (0)