fund-cli 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fund_cli/__init__.py +13 -0
- fund_cli/__main__.py +10 -0
- fund_cli/ai/__init__.py +21 -0
- fund_cli/ai/analyzer.py +360 -0
- fund_cli/ai/prompts.py +244 -0
- fund_cli/ai/providers.py +286 -0
- fund_cli/analysis/__init__.py +17 -0
- fund_cli/analysis/attribution.py +161 -0
- fund_cli/analysis/backtest.py +75 -0
- fund_cli/analysis/holding.py +217 -0
- fund_cli/analysis/manager.py +133 -0
- fund_cli/analysis/performance.py +440 -0
- fund_cli/analysis/portfolio.py +152 -0
- fund_cli/analysis/risk.py +300 -0
- fund_cli/cli.py +98 -0
- fund_cli/commands/__init__.py +9 -0
- fund_cli/commands/ai_cmd.py +464 -0
- fund_cli/commands/analyze_cmd.py +418 -0
- fund_cli/commands/compare_cmd.py +264 -0
- fund_cli/commands/config_cmd.py +97 -0
- fund_cli/commands/data_cmd.py +106 -0
- fund_cli/commands/filter_cmd.py +286 -0
- fund_cli/commands/holding_cmd.py +140 -0
- fund_cli/commands/interactive_cmd.py +84 -0
- fund_cli/commands/main.py +17 -0
- fund_cli/commands/manager_cmd.py +74 -0
- fund_cli/commands/monitor_cmd.py +113 -0
- fund_cli/commands/optimize_cmd.py +192 -0
- fund_cli/config.py +163 -0
- fund_cli/core/__init__.py +8 -0
- fund_cli/core/analyzer.py +46 -0
- fund_cli/core/data_manager.py +231 -0
- fund_cli/core/data_quality.py +162 -0
- fund_cli/core/monitor.py +230 -0
- fund_cli/core/optimizer.py +50 -0
- fund_cli/core/optimizers/__init__.py +13 -0
- fund_cli/core/optimizers/efficient_frontier.py +91 -0
- fund_cli/core/optimizers/max_sharpe.py +54 -0
- fund_cli/core/optimizers/mean_variance.py +84 -0
- fund_cli/core/optimizers/risk_parity.py +60 -0
- fund_cli/core/reporter.py +67 -0
- fund_cli/core/reporters/__init__.py +6 -0
- fund_cli/core/reporters/html_reporter.py +62 -0
- fund_cli/core/reporters/markdown_reporter.py +40 -0
- fund_cli/core/screener.py +142 -0
- fund_cli/data/__init__.py +6 -0
- fund_cli/data/adapters/__init__.py +7 -0
- fund_cli/data/adapters/akshare_adapter.py +442 -0
- fund_cli/data/adapters/tushare_adapter.py +254 -0
- fund_cli/data/adapters/wind_adapter.py +78 -0
- fund_cli/data/base.py +209 -0
- fund_cli/data/cache.py +192 -0
- fund_cli/data/models.py +248 -0
- fund_cli/utils/__init__.py +6 -0
- fund_cli/utils/decorators.py +88 -0
- fund_cli/utils/helpers.py +127 -0
- fund_cli/utils/validators.py +77 -0
- fund_cli/views/__init__.py +6 -0
- fund_cli/views/charts.py +120 -0
- fund_cli/views/reports.py +82 -0
- fund_cli/views/tables.py +124 -0
- fund_cli-2.0.0.dist-info/METADATA +183 -0
- fund_cli-2.0.0.dist-info/RECORD +66 -0
- fund_cli-2.0.0.dist-info/WHEEL +4 -0
- fund_cli-2.0.0.dist-info/entry_points.txt +3 -0
- fund_cli-2.0.0.dist-info/licenses/LICENSE +21 -0
fund_cli/__init__.py
ADDED
fund_cli/__main__.py
ADDED
fund_cli/ai/__init__.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""AI模块 - LLM提供商、AI分析服务、提示词模板"""
|
|
2
|
+
|
|
3
|
+
from fund_cli.ai.analyzer import AIAnalyzer
|
|
4
|
+
from fund_cli.ai.prompts import PromptTemplates
|
|
5
|
+
from fund_cli.ai.providers import (
|
|
6
|
+
LiteLLMProvider,
|
|
7
|
+
LLMProvider,
|
|
8
|
+
OpenAIProvider,
|
|
9
|
+
QwenProvider,
|
|
10
|
+
get_provider,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"LLMProvider",
|
|
15
|
+
"OpenAIProvider",
|
|
16
|
+
"QwenProvider",
|
|
17
|
+
"LiteLLMProvider",
|
|
18
|
+
"get_provider",
|
|
19
|
+
"AIAnalyzer",
|
|
20
|
+
"PromptTemplates",
|
|
21
|
+
]
|
fund_cli/ai/analyzer.py
ADDED
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AI 分析服务(V2.0 实现)
|
|
3
|
+
|
|
4
|
+
使用 LLM 进行基金分析、报告生成等功能。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import re
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from fund_cli.ai.prompts import PromptTemplates
|
|
14
|
+
from fund_cli.ai.providers import LLMProvider, get_provider
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AIAnalyzer:
|
|
18
|
+
"""
|
|
19
|
+
AI 分析服务
|
|
20
|
+
|
|
21
|
+
使用 LLM 进行基金分析、报告生成等功能。
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, provider: LLMProvider | None = None):
|
|
25
|
+
"""
|
|
26
|
+
初始化 AI 分析服务
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
provider: LLM 提供商实例,如果为None则使用默认配置创建
|
|
30
|
+
"""
|
|
31
|
+
self.provider = provider or get_provider()
|
|
32
|
+
self.prompts = PromptTemplates()
|
|
33
|
+
|
|
34
|
+
def summarize_fund(self, fund_code: str, fund_data: dict[str, Any]) -> str:
|
|
35
|
+
"""
|
|
36
|
+
生成基金分析摘要
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
fund_code: 基金代码
|
|
40
|
+
fund_data: 基金数据字典,包含info、nav、metrics等
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
AI生成的基金摘要文本
|
|
44
|
+
"""
|
|
45
|
+
info = fund_data.get("info", {})
|
|
46
|
+
metrics = fund_data.get("metrics", {})
|
|
47
|
+
|
|
48
|
+
prompt_data = {
|
|
49
|
+
"fund_code": fund_code,
|
|
50
|
+
"fund_name": info.get("name", "未知"),
|
|
51
|
+
"fund_type": info.get("type", "未知"),
|
|
52
|
+
"manager": info.get("manager", "未知"),
|
|
53
|
+
"total_return": metrics.get("total_return", 0),
|
|
54
|
+
"cagr": metrics.get("cagr", 0),
|
|
55
|
+
"sharpe": metrics.get("sharpe_ratio", 0),
|
|
56
|
+
"max_drawdown": metrics.get("max_drawdown", 0),
|
|
57
|
+
"volatility": metrics.get("volatility", 0),
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
prompt = self.prompts.format_summary_prompt(prompt_data)
|
|
61
|
+
return self.provider.generate(prompt)
|
|
62
|
+
|
|
63
|
+
def compare_funds(self, fund_codes: list[str], funds_data: list[dict]) -> str:
|
|
64
|
+
"""
|
|
65
|
+
对比分析多只基金
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
fund_codes: 基金代码列表
|
|
69
|
+
funds_data: 基金数据列表
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
AI生成的对比分析报告
|
|
73
|
+
"""
|
|
74
|
+
funds_text = []
|
|
75
|
+
for i, data in enumerate(funds_data):
|
|
76
|
+
code = fund_codes[i] if i < len(fund_codes) else data.get("code", "")
|
|
77
|
+
info = data.get("info", {})
|
|
78
|
+
metrics = data.get("metrics", {})
|
|
79
|
+
|
|
80
|
+
fund_text = f"""
|
|
81
|
+
基金 {i + 1}: {code}
|
|
82
|
+
- 名称: {info.get('name', '未知')}
|
|
83
|
+
- 类型: {info.get('type', '未知')}
|
|
84
|
+
- 年化收益: {metrics.get('cagr', 0)}%
|
|
85
|
+
- 夏普比率: {metrics.get('sharpe_ratio', 0)}
|
|
86
|
+
- 最大回撤: {metrics.get('max_drawdown', 0)}%
|
|
87
|
+
- 波动率: {metrics.get('volatility', 0)}%
|
|
88
|
+
"""
|
|
89
|
+
funds_text.append(fund_text)
|
|
90
|
+
|
|
91
|
+
prompt = self.prompts.format_compare_prompt("\n".join(funds_text))
|
|
92
|
+
return self.provider.generate(prompt)
|
|
93
|
+
|
|
94
|
+
def investment_advice(
|
|
95
|
+
self, fund_code: str, fund_data: dict[str, Any], risk_profile: str
|
|
96
|
+
) -> dict[str, str]:
|
|
97
|
+
"""
|
|
98
|
+
生成投资建议
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
fund_code: 基金代码
|
|
102
|
+
fund_data: 基金数据
|
|
103
|
+
risk_profile: 风险偏好 (conservative/moderate/aggressive)
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
结构化投资建议字典
|
|
107
|
+
"""
|
|
108
|
+
info = fund_data.get("info", {})
|
|
109
|
+
metrics = fund_data.get("metrics", {})
|
|
110
|
+
|
|
111
|
+
fund_info = {
|
|
112
|
+
"name": info.get("name", "未知"),
|
|
113
|
+
"code": fund_code,
|
|
114
|
+
"type": info.get("type", "未知"),
|
|
115
|
+
"cagr": metrics.get("cagr", 0),
|
|
116
|
+
"sharpe": metrics.get("sharpe_ratio", 0),
|
|
117
|
+
"max_drawdown": metrics.get("max_drawdown", 0),
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
prompt = self.prompts.format_investment_advice_prompt(fund_info, risk_profile)
|
|
121
|
+
response = self.provider.generate(prompt)
|
|
122
|
+
|
|
123
|
+
return self._parse_json_response(response)
|
|
124
|
+
|
|
125
|
+
def risk_assessment(
|
|
126
|
+
self, fund_code: str, fund_data: dict[str, Any], detailed: bool = False
|
|
127
|
+
) -> dict[str, str]:
|
|
128
|
+
"""
|
|
129
|
+
深度风险评估
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
fund_code: 基金代码
|
|
133
|
+
fund_data: 基金数据
|
|
134
|
+
detailed: 是否生成详细分析
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
风险评估结果字典
|
|
138
|
+
"""
|
|
139
|
+
info = fund_data.get("info", {})
|
|
140
|
+
nav_data = fund_data.get("nav", [])
|
|
141
|
+
|
|
142
|
+
# 计算风险指标
|
|
143
|
+
risk_metrics = self._calculate_risk_metrics(nav_data)
|
|
144
|
+
|
|
145
|
+
fund_info = {
|
|
146
|
+
"name": info.get("name", "未知"),
|
|
147
|
+
"code": fund_code,
|
|
148
|
+
"max_drawdown": risk_metrics.get("max_drawdown", 0),
|
|
149
|
+
"volatility": risk_metrics.get("volatility", 0),
|
|
150
|
+
"downside_deviation": risk_metrics.get("downside_deviation", 0),
|
|
151
|
+
"sortino_ratio": risk_metrics.get("sortino_ratio", 0),
|
|
152
|
+
"beta": risk_metrics.get("beta", 0),
|
|
153
|
+
"risk_events": "无重大风险事件", # 可从历史数据中提取
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
prompt = self.prompts.format_risk_assessment_prompt(fund_info, detailed)
|
|
157
|
+
response = self.provider.generate(prompt)
|
|
158
|
+
|
|
159
|
+
return self._parse_json_response(response)
|
|
160
|
+
|
|
161
|
+
def market_insight(
|
|
162
|
+
self, fund_code: str, fund_data: dict[str, Any], market_context: str | None = None
|
|
163
|
+
) -> str:
|
|
164
|
+
"""
|
|
165
|
+
市场解读分析
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
fund_code: 基金代码
|
|
169
|
+
fund_data: 基金数据
|
|
170
|
+
market_context: 市场环境描述(可选)
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
市场解读文本
|
|
174
|
+
"""
|
|
175
|
+
info = fund_data.get("info", {})
|
|
176
|
+
nav_data = fund_data.get("nav", [])
|
|
177
|
+
|
|
178
|
+
# 计算近期收益
|
|
179
|
+
recent_return = 0
|
|
180
|
+
if len(nav_data) >= 2:
|
|
181
|
+
recent_return = (nav_data[-1] - nav_data[0]) / nav_data[0] * 100
|
|
182
|
+
|
|
183
|
+
fund_info = {
|
|
184
|
+
"name": info.get("name", "未知"),
|
|
185
|
+
"code": fund_code,
|
|
186
|
+
"recent_return": recent_return,
|
|
187
|
+
"rank_in_category": "前30%", # 可从数据中获取
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
prompt = self.prompts.format_market_insight_prompt(fund_info, market_context)
|
|
191
|
+
return self.provider.generate(prompt)
|
|
192
|
+
|
|
193
|
+
def portfolio_review(self, portfolio_data: dict[str, Any]) -> dict[str, str]:
|
|
194
|
+
"""
|
|
195
|
+
投资组合分析
|
|
196
|
+
|
|
197
|
+
Args:
|
|
198
|
+
portfolio_data: 组合数据,包含持仓、权重、历史收益等
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
组合分析结果
|
|
202
|
+
"""
|
|
203
|
+
# 计算组合指标
|
|
204
|
+
portfolio_metrics = self._calculate_portfolio_metrics(portfolio_data)
|
|
205
|
+
|
|
206
|
+
portfolio_info = {
|
|
207
|
+
"funds": portfolio_data.get("funds", []),
|
|
208
|
+
"weights": portfolio_data.get("weights", []),
|
|
209
|
+
"expected_return": portfolio_metrics.get("expected_return", 0),
|
|
210
|
+
"expected_volatility": portfolio_metrics.get("expected_volatility", 0),
|
|
211
|
+
"portfolio_sharpe": portfolio_metrics.get("portfolio_sharpe", 0),
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
prompt = self.prompts.format_portfolio_review_prompt(portfolio_info)
|
|
215
|
+
response = self.provider.generate(prompt)
|
|
216
|
+
|
|
217
|
+
return self._parse_json_response(response)
|
|
218
|
+
|
|
219
|
+
def generate_report(
|
|
220
|
+
self, fund_code: str, fund_info: dict[str, Any], metrics: dict[str, Any]
|
|
221
|
+
) -> str:
|
|
222
|
+
"""
|
|
223
|
+
生成分析报告
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
fund_code: 基金代码
|
|
227
|
+
fund_info: 基金信息
|
|
228
|
+
metrics: 分析指标
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
报告文本
|
|
232
|
+
"""
|
|
233
|
+
prompt_data = {
|
|
234
|
+
"fund_code": fund_code,
|
|
235
|
+
"fund_name": fund_info.get("name", "未知"),
|
|
236
|
+
"fund_type": fund_info.get("type", "未知"),
|
|
237
|
+
"manager": fund_info.get("manager", "未知"),
|
|
238
|
+
"total_return": metrics.get("total_return", 0),
|
|
239
|
+
"cagr": metrics.get("cagr", 0),
|
|
240
|
+
"sharpe": metrics.get("sharpe_ratio", 0),
|
|
241
|
+
"max_drawdown": metrics.get("max_drawdown", 0),
|
|
242
|
+
"volatility": metrics.get("volatility", 0),
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
prompt = self.prompts.format_summary_prompt(prompt_data)
|
|
246
|
+
return self.provider.generate(prompt)
|
|
247
|
+
|
|
248
|
+
def _parse_json_response(self, response: str) -> dict[str, str]:
|
|
249
|
+
"""
|
|
250
|
+
解析JSON格式的AI响应
|
|
251
|
+
|
|
252
|
+
Args:
|
|
253
|
+
response: AI响应文本
|
|
254
|
+
|
|
255
|
+
Returns:
|
|
256
|
+
解析后的字典
|
|
257
|
+
"""
|
|
258
|
+
# 尝试提取JSON内容
|
|
259
|
+
json_match = re.search(r"\{[\s\S]*\}", response)
|
|
260
|
+
if json_match:
|
|
261
|
+
try:
|
|
262
|
+
return json.loads(json_match.group())
|
|
263
|
+
except json.JSONDecodeError:
|
|
264
|
+
pass
|
|
265
|
+
|
|
266
|
+
# 如果JSON解析失败,返回结构化文本
|
|
267
|
+
return {"raw_response": response}
|
|
268
|
+
|
|
269
|
+
def _calculate_risk_metrics(self, nav_data: list) -> dict[str, float]:
|
|
270
|
+
"""
|
|
271
|
+
计算风险指标
|
|
272
|
+
|
|
273
|
+
Args:
|
|
274
|
+
nav_data: 净值数据列表
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
风险指标字典
|
|
278
|
+
"""
|
|
279
|
+
if not nav_data or len(nav_data) < 2:
|
|
280
|
+
return {
|
|
281
|
+
"max_drawdown": 0,
|
|
282
|
+
"volatility": 0,
|
|
283
|
+
"downside_deviation": 0,
|
|
284
|
+
"sortino_ratio": 0,
|
|
285
|
+
"beta": 0,
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
import numpy as np
|
|
289
|
+
|
|
290
|
+
# 计算收益率
|
|
291
|
+
returns = np.diff(nav_data) / nav_data[:-1]
|
|
292
|
+
|
|
293
|
+
# 最大回撤
|
|
294
|
+
cumulative = np.cumprod(1 + returns)
|
|
295
|
+
running_max = np.maximum.accumulate(cumulative)
|
|
296
|
+
drawdown = (cumulative - running_max) / running_max
|
|
297
|
+
max_drawdown = np.min(drawdown) * 100 if len(drawdown) > 0 else 0
|
|
298
|
+
|
|
299
|
+
# 波动率
|
|
300
|
+
volatility = np.std(returns) * np.sqrt(252) * 100 if len(returns) > 0 else 0
|
|
301
|
+
|
|
302
|
+
# 下行标准差
|
|
303
|
+
downside_returns = returns[returns < 0]
|
|
304
|
+
downside_deviation = (
|
|
305
|
+
np.std(downside_returns) * np.sqrt(252) * 100 if len(downside_returns) > 0 else 0
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
# 索提诺比率
|
|
309
|
+
avg_return = np.mean(returns) * 252 * 100 if len(returns) > 0 else 0
|
|
310
|
+
sortino_ratio = avg_return / downside_deviation if downside_deviation > 0 else 0
|
|
311
|
+
|
|
312
|
+
# Beta (简化计算,假设市场收益率为0)
|
|
313
|
+
beta = 1.0
|
|
314
|
+
|
|
315
|
+
return {
|
|
316
|
+
"max_drawdown": abs(max_drawdown),
|
|
317
|
+
"volatility": volatility,
|
|
318
|
+
"downside_deviation": downside_deviation,
|
|
319
|
+
"sortino_ratio": sortino_ratio,
|
|
320
|
+
"beta": beta,
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
def _calculate_portfolio_metrics(self, portfolio_data: dict) -> dict[str, float]:
|
|
324
|
+
"""
|
|
325
|
+
计算组合指标
|
|
326
|
+
|
|
327
|
+
Args:
|
|
328
|
+
portfolio_data: 组合数据
|
|
329
|
+
|
|
330
|
+
Returns:
|
|
331
|
+
组合指标字典
|
|
332
|
+
"""
|
|
333
|
+
funds = portfolio_data.get("funds", [])
|
|
334
|
+
weights = portfolio_data.get("weights", [])
|
|
335
|
+
|
|
336
|
+
if not funds or not weights:
|
|
337
|
+
return {
|
|
338
|
+
"expected_return": 0,
|
|
339
|
+
"expected_volatility": 0,
|
|
340
|
+
"portfolio_sharpe": 0,
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
# 计算加权平均收益
|
|
344
|
+
total_return = 0
|
|
345
|
+
total_sharpe = 0
|
|
346
|
+
|
|
347
|
+
for i, fund in enumerate(funds):
|
|
348
|
+
weight = weights[i] if i < len(weights) else 0
|
|
349
|
+
metrics = fund.get("metrics", {})
|
|
350
|
+
total_return += metrics.get("cagr", 0) * weight
|
|
351
|
+
total_sharpe += metrics.get("sharpe_ratio", 0) * weight
|
|
352
|
+
|
|
353
|
+
# 简化计算,假设波动率为10%
|
|
354
|
+
volatility = 10.0
|
|
355
|
+
|
|
356
|
+
return {
|
|
357
|
+
"expected_return": total_return,
|
|
358
|
+
"expected_volatility": volatility,
|
|
359
|
+
"portfolio_sharpe": total_sharpe,
|
|
360
|
+
}
|
fund_cli/ai/prompts.py
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AI 提示词模板(V2.0 实现)
|
|
3
|
+
|
|
4
|
+
管理用于基金分析的提示词模板。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class PromptTemplates:
|
|
11
|
+
"""提示词模板管理"""
|
|
12
|
+
|
|
13
|
+
FUND_SUMMARY = """
|
|
14
|
+
你是一位专业的基金分析师。请根据以下基金数据生成一份简洁的分析摘要。
|
|
15
|
+
|
|
16
|
+
基金信息:
|
|
17
|
+
- 代码:{fund_code}
|
|
18
|
+
- 名称:{fund_name}
|
|
19
|
+
- 类型:{fund_type}
|
|
20
|
+
- 基金经理:{manager}
|
|
21
|
+
|
|
22
|
+
业绩指标:
|
|
23
|
+
- 总收益率:{total_return}%
|
|
24
|
+
- 年化收益率:{cagr}%
|
|
25
|
+
- 夏普比率:{sharpe}
|
|
26
|
+
- 最大回撤:{max_drawdown}%
|
|
27
|
+
- 年化波动率:{volatility}%
|
|
28
|
+
|
|
29
|
+
请从以下维度分析:
|
|
30
|
+
1. 收益能力
|
|
31
|
+
2. 风险控制
|
|
32
|
+
3. 综合评价
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
FUND_COMPARE = """
|
|
36
|
+
你是一位专业的基金分析师。请对比分析以下基金。
|
|
37
|
+
|
|
38
|
+
{funds_data}
|
|
39
|
+
|
|
40
|
+
请从以下维度对比分析:
|
|
41
|
+
1. 收益对比
|
|
42
|
+
2. 风险对比
|
|
43
|
+
3. 风险调整收益对比
|
|
44
|
+
4. 综合推荐
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
RISK_ANALYSIS = """
|
|
48
|
+
你是一位专业的风险管理分析师。请分析以下基金的风险状况。
|
|
49
|
+
|
|
50
|
+
基金:{fund_name}({fund_code})
|
|
51
|
+
|
|
52
|
+
风险指标:
|
|
53
|
+
- 年化波动率:{volatility}%
|
|
54
|
+
- 最大回撤:{max_drawdown}%
|
|
55
|
+
- VaR(95%):{var_95}%
|
|
56
|
+
- VaR(99%):{var_99}%
|
|
57
|
+
- 偏度:{skewness}
|
|
58
|
+
- 峰度:{kurtosis}
|
|
59
|
+
|
|
60
|
+
请分析:
|
|
61
|
+
1. 整体风险水平
|
|
62
|
+
2. 尾部风险特征
|
|
63
|
+
3. 风险管理建议
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
INVESTMENT_ADVICE = """
|
|
67
|
+
你是一位专业的投资顾问。请基于以下基金数据给出投资建议。
|
|
68
|
+
|
|
69
|
+
基金:{fund_name}({fund_code})
|
|
70
|
+
类型:{fund_type}
|
|
71
|
+
|
|
72
|
+
业绩指标:
|
|
73
|
+
- 年化收益:{cagr}%
|
|
74
|
+
- 夏普比率:{sharpe}
|
|
75
|
+
- 最大回撤:{max_drawdown}%
|
|
76
|
+
|
|
77
|
+
投资者风险偏好:{risk_profile}
|
|
78
|
+
|
|
79
|
+
请给出:
|
|
80
|
+
1. 是否适合该投资者(是/否/谨慎考虑)
|
|
81
|
+
2. 建议配置比例(如适用)
|
|
82
|
+
3. 关键风险提示
|
|
83
|
+
4. 持有期建议
|
|
84
|
+
|
|
85
|
+
请以JSON格式输出结果,格式如下:
|
|
86
|
+
{{
|
|
87
|
+
"suitability": "是/否/谨慎考虑",
|
|
88
|
+
"allocation": "建议配置比例",
|
|
89
|
+
"risk_warning": "关键风险提示",
|
|
90
|
+
"holding_period": "持有期建议"
|
|
91
|
+
}}
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
MARKET_INSIGHT = """
|
|
95
|
+
你是一位市场分析师。请结合当前市场环境分析该基金表现。
|
|
96
|
+
|
|
97
|
+
基金:{fund_name}({fund_code})
|
|
98
|
+
近期收益:{recent_return}%
|
|
99
|
+
同类排名:{rank_in_category}
|
|
100
|
+
|
|
101
|
+
市场环境:{market_context}
|
|
102
|
+
|
|
103
|
+
请分析:
|
|
104
|
+
1. 基金表现与市场关系
|
|
105
|
+
2. 基金经理应对能力
|
|
106
|
+
3. 未来展望
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
PORTFOLIO_REVIEW = """
|
|
110
|
+
你是一位投资组合顾问。请对以下组合进行整体评估。
|
|
111
|
+
|
|
112
|
+
组合配置:
|
|
113
|
+
{portfolio_config}
|
|
114
|
+
|
|
115
|
+
组合指标:
|
|
116
|
+
- 预期收益:{expected_return}%
|
|
117
|
+
- 预期波动:{expected_volatility}%
|
|
118
|
+
- 夏普比率:{portfolio_sharpe}
|
|
119
|
+
|
|
120
|
+
请给出:
|
|
121
|
+
1. 组合整体评价
|
|
122
|
+
2. 配置优化建议
|
|
123
|
+
3. 风险分散度评估
|
|
124
|
+
|
|
125
|
+
请以JSON格式输出结果,格式如下:
|
|
126
|
+
{{
|
|
127
|
+
"overall_assessment": "组合整体评价",
|
|
128
|
+
"optimization_suggestions": "配置优化建议",
|
|
129
|
+
"diversification": "风险分散度评估"
|
|
130
|
+
}}
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
RISK_ASSESSMENT = """
|
|
134
|
+
你是一位风险管理专家。请对以下基金进行深度风险评估。
|
|
135
|
+
|
|
136
|
+
基金:{fund_name}({fund_code})
|
|
137
|
+
|
|
138
|
+
风险指标:
|
|
139
|
+
- 最大回撤:{max_drawdown}%
|
|
140
|
+
- 波动率:{volatility}%
|
|
141
|
+
- 下行标准差:{downside_deviation}%
|
|
142
|
+
- 索提诺比率:{sortino_ratio}
|
|
143
|
+
- Beta系数:{beta}
|
|
144
|
+
|
|
145
|
+
历史风险事件:
|
|
146
|
+
{risk_events}
|
|
147
|
+
|
|
148
|
+
请给出:
|
|
149
|
+
1. 风险等级(低/中/高/极高)
|
|
150
|
+
2. 主要风险因素分析
|
|
151
|
+
3. 风险预警(如有)
|
|
152
|
+
4. 风险控制建议
|
|
153
|
+
{detail_section}
|
|
154
|
+
|
|
155
|
+
请以JSON格式输出结果,格式如下:
|
|
156
|
+
{{
|
|
157
|
+
"risk_level": "风险等级",
|
|
158
|
+
"main_risks": "主要风险因素",
|
|
159
|
+
"warnings": "风险预警",
|
|
160
|
+
"control_suggestions": "风险控制建议"
|
|
161
|
+
}}
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
@staticmethod
|
|
165
|
+
def format_summary_prompt(data: dict[str, Any]) -> str:
|
|
166
|
+
"""格式化基金摘要提示词"""
|
|
167
|
+
return PromptTemplates.FUND_SUMMARY.format(**data)
|
|
168
|
+
|
|
169
|
+
@staticmethod
|
|
170
|
+
def format_compare_prompt(funds_data: str) -> str:
|
|
171
|
+
"""格式化基金对比提示词"""
|
|
172
|
+
return PromptTemplates.FUND_COMPARE.format(funds_data=funds_data)
|
|
173
|
+
|
|
174
|
+
@staticmethod
|
|
175
|
+
def format_risk_prompt(data: dict[str, Any]) -> str:
|
|
176
|
+
"""格式化风险分析提示词"""
|
|
177
|
+
return PromptTemplates.RISK_ANALYSIS.format(**data)
|
|
178
|
+
|
|
179
|
+
@staticmethod
|
|
180
|
+
def format_investment_advice_prompt(fund_data: dict[str, Any], risk_profile: str) -> str:
|
|
181
|
+
"""格式化投资建议提示词"""
|
|
182
|
+
return PromptTemplates.INVESTMENT_ADVICE.format(
|
|
183
|
+
fund_name=fund_data.get("name", ""),
|
|
184
|
+
fund_code=fund_data.get("code", ""),
|
|
185
|
+
fund_type=fund_data.get("type", ""),
|
|
186
|
+
cagr=fund_data.get("cagr", 0),
|
|
187
|
+
sharpe=fund_data.get("sharpe", 0),
|
|
188
|
+
max_drawdown=fund_data.get("max_drawdown", 0),
|
|
189
|
+
risk_profile=risk_profile,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
@staticmethod
|
|
193
|
+
def format_market_insight_prompt(
|
|
194
|
+
fund_data: dict[str, Any], market_context: str | None = None
|
|
195
|
+
) -> str:
|
|
196
|
+
"""格式化市场解读提示词"""
|
|
197
|
+
return PromptTemplates.MARKET_INSIGHT.format(
|
|
198
|
+
fund_name=fund_data.get("name", ""),
|
|
199
|
+
fund_code=fund_data.get("code", ""),
|
|
200
|
+
recent_return=fund_data.get("recent_return", 0),
|
|
201
|
+
rank_in_category=fund_data.get("rank_in_category", "未知"),
|
|
202
|
+
market_context=market_context or "当前市场环境正常",
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
@staticmethod
|
|
206
|
+
def format_portfolio_review_prompt(portfolio_data: dict[str, Any]) -> str:
|
|
207
|
+
"""格式化组合分析提示词"""
|
|
208
|
+
funds = portfolio_data.get("funds", [])
|
|
209
|
+
weights = portfolio_data.get("weights", [])
|
|
210
|
+
|
|
211
|
+
portfolio_config = ""
|
|
212
|
+
for i, fund in enumerate(funds):
|
|
213
|
+
weight = weights[i] if i < len(weights) else 0
|
|
214
|
+
portfolio_config += f"- {fund.get('code', '')}: {weight * 100:.1f}%\n"
|
|
215
|
+
|
|
216
|
+
return PromptTemplates.PORTFOLIO_REVIEW.format(
|
|
217
|
+
portfolio_config=portfolio_config,
|
|
218
|
+
expected_return=portfolio_data.get("expected_return", 0),
|
|
219
|
+
expected_volatility=portfolio_data.get("expected_volatility", 0),
|
|
220
|
+
portfolio_sharpe=portfolio_data.get("portfolio_sharpe", 0),
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
@staticmethod
|
|
224
|
+
def format_risk_assessment_prompt(fund_data: dict[str, Any], detailed: bool = False) -> str:
|
|
225
|
+
"""格式化风险评估提示词"""
|
|
226
|
+
detail_section = ""
|
|
227
|
+
if detailed:
|
|
228
|
+
detail_section = """
|
|
229
|
+
5. 详细风险分析报告
|
|
230
|
+
6. 历史风险事件回顾
|
|
231
|
+
7. 压力测试结果
|
|
232
|
+
"""
|
|
233
|
+
|
|
234
|
+
return PromptTemplates.RISK_ASSESSMENT.format(
|
|
235
|
+
fund_name=fund_data.get("name", ""),
|
|
236
|
+
fund_code=fund_data.get("code", ""),
|
|
237
|
+
max_drawdown=fund_data.get("max_drawdown", 0),
|
|
238
|
+
volatility=fund_data.get("volatility", 0),
|
|
239
|
+
downside_deviation=fund_data.get("downside_deviation", 0),
|
|
240
|
+
sortino_ratio=fund_data.get("sortino_ratio", 0),
|
|
241
|
+
beta=fund_data.get("beta", 0),
|
|
242
|
+
risk_events=fund_data.get("risk_events", "无重大风险事件"),
|
|
243
|
+
detail_section=detail_section,
|
|
244
|
+
)
|