erlangshen 0.1.0
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.
- package/.claude/agents/equity-agent.md +26 -0
- package/.claude/agents/macro-agent.md +25 -0
- package/.claude/commands/analyze.md +40 -0
- package/.claude/commands/macro.md +29 -0
- package/.claude/settings.json +12 -0
- package/CODEX_GOAL.md +46 -0
- package/README.md +206 -0
- package/bin/cli.js +67 -0
- package/bin/erlangshen +2 -0
- package/bin/xiaoergod +2 -0
- package/frontend/index.html +700 -0
- package/knowledge/crypto_guide.md +147 -0
- package/knowledge/economic_indicators.md +125 -0
- package/knowledge/financial_glossary.md +148 -0
- package/knowledge/first_principles.md +50 -0
- package/knowledge/first_principles_deep.md +115 -0
- package/knowledge/global_markets.md +173 -0
- package/knowledge/insights.md +141 -0
- package/knowledge/market_basics.md +116 -0
- package/knowledge/memos/session_20260513_003616.json +6 -0
- package/knowledge/memos/session_20260513_003822.json +6 -0
- package/knowledge/risk_management.md +151 -0
- package/knowledge/team_context.md +42 -0
- package/knowledge/trading_strategies.md +114 -0
- package/package.json +42 -0
- package/requirements.txt +14 -0
- package/scripts/postinstall.js +188 -0
- package/scripts/preuninstall.js +22 -0
- package/src/__init__.py +4 -0
- package/src/__pycache__/__init__.cpython-313.pyc +0 -0
- package/src/agents/__init__.py +3 -0
- package/src/agents/base.py +103 -0
- package/src/agents/base_agent.py +86 -0
- package/src/agents/equity.py +136 -0
- package/src/agents/equity_agent.py +91 -0
- package/src/agents/erlang.py +165 -0
- package/src/agents/macro.py +137 -0
- package/src/agents/macro_agent.py +81 -0
- package/src/agents/multi_asset.py +147 -0
- package/src/agents/multi_asset_agent.py +87 -0
- package/src/api/__init__.py +1 -0
- package/src/api/__pycache__/__init__.cpython-313.pyc +0 -0
- package/src/api/__pycache__/server.cpython-313.pyc +0 -0
- package/src/api/cli.py +435 -0
- package/src/api/cli_enhanced.py +537 -0
- package/src/api/server.py +266 -0
- package/src/brain.py +200 -0
- package/src/cli.py +153 -0
- package/src/commands/__init__.py +3 -0
- package/src/commands/analyze.py +131 -0
- package/src/commands/macro.py +100 -0
- package/src/commands/memo.py +216 -0
- package/src/commands/portfolio.py +154 -0
- package/src/commands/report.py +228 -0
- package/src/commands/risk.py +183 -0
- package/src/commands/search.py +183 -0
- package/src/commands/stock.py +124 -0
- package/src/config.py +327 -0
- package/src/core/__init__.py +1 -0
- package/src/core/brain.py +645 -0
- package/src/core/cerebellum.py +175 -0
- package/src/core/investment_universe.py +423 -0
- package/src/core/knowledge.py +207 -0
- package/src/core/memory.py +115 -0
- package/src/hooks/__init__.py +3 -0
- package/src/hooks/session_end.py +57 -0
- package/src/hooks/session_start.py +75 -0
- package/src/knowledge/__init__.py +1 -0
- package/src/mcp/__init__.py +3 -0
- package/src/mcp/feishu.py +331 -0
- package/src/mcp/fund_tools.py +323 -0
- package/src/mcp/macro.py +452 -0
- package/src/mcp/market.py +331 -0
- package/src/mcp/registry.py +168 -0
- package/src/network/__init__.py +15 -0
- package/src/network/detector.py +125 -0
- package/src/network/proxy.py +199 -0
- package/src/network/router.py +103 -0
- package/src/prompts/__init__.py +1 -0
- package/src/prompts/analysis_framework.md +164 -0
- package/src/prompts/persona.md +65 -0
- package/src/prompts/report_template.md +144 -0
- package/src/skills/__init__.py +3 -0
- package/src/skills/framework.py +105 -0
- package/src/skills/templates.py +342 -0
- package/src/tools/__init__.py +1 -0
- package/src/tools/file_tools.py +209 -0
- package/src/tools/macro_tools.py +152 -0
- package/src/tools/market_tools.py +1172 -0
- package/src/tools/registry.py +398 -0
- package/src/tools/search_tools.py +777 -0
- package/tests/__init__.py +1 -0
- package/tests/test_erlangshen.py +140 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"""
|
|
2
|
+
/analyze 命令 - 综合分析
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from src.agents.macro import MacroAgent
|
|
7
|
+
from src.agents.equity import EquityAgent
|
|
8
|
+
from src.agents.multi_asset import MultiAssetAgent
|
|
9
|
+
from src.brain import Brain
|
|
10
|
+
from src.mcp.registry import MCPRegistry
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AnalyzeCommand:
|
|
14
|
+
"""
|
|
15
|
+
综合分析命令处理器
|
|
16
|
+
|
|
17
|
+
用法:
|
|
18
|
+
/analyze A股当前走势
|
|
19
|
+
/analyze 茅台投资价值
|
|
20
|
+
/analyze 黄金避险情绪
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, brain: Brain, mcp: MCPRegistry):
|
|
24
|
+
self.brain = brain
|
|
25
|
+
self.mcp = mcp
|
|
26
|
+
self.macro_agent = MacroAgent(brain, mcp)
|
|
27
|
+
self.equity_agent = EquityAgent(brain, mcp)
|
|
28
|
+
self.multi_asset_agent = MultiAssetAgent(brain, mcp)
|
|
29
|
+
|
|
30
|
+
async def execute(self, args: str) -> str:
|
|
31
|
+
"""
|
|
32
|
+
执行分析
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
args: 分析查询
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
分析结果
|
|
39
|
+
"""
|
|
40
|
+
if not args:
|
|
41
|
+
return self._help()
|
|
42
|
+
|
|
43
|
+
# 意图识别
|
|
44
|
+
intent = self._classify_intent(args)
|
|
45
|
+
|
|
46
|
+
if intent == "macro":
|
|
47
|
+
return await self.macro_agent.process(args)
|
|
48
|
+
elif intent == "equity":
|
|
49
|
+
return await self.equity_agent.process(args)
|
|
50
|
+
elif intent == "multi_asset":
|
|
51
|
+
return await self.multi_asset_agent.process(args)
|
|
52
|
+
else:
|
|
53
|
+
# 默认综合分析
|
|
54
|
+
return await self._comprehensive_analysis(args)
|
|
55
|
+
|
|
56
|
+
def _classify_intent(self, query: str) -> str:
|
|
57
|
+
"""
|
|
58
|
+
分类查询意图
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
intent: macro/equity/multi_asset
|
|
62
|
+
"""
|
|
63
|
+
query_lower = query.lower()
|
|
64
|
+
|
|
65
|
+
# 宏观关键词
|
|
66
|
+
macro_keywords = ["宏观", "经济", "gdp", "cpi", "ppi", "pmi", "利率", "汇率",
|
|
67
|
+
"货币", "财政", "政策", "出口", "进口", "社融", "m2"]
|
|
68
|
+
|
|
69
|
+
# 股票关键词
|
|
70
|
+
equity_keywords = ["股票", "股价", "茅台", "腾讯", "苹果", "估值", "财报",
|
|
71
|
+
"营收", "利润", "板块", "行业", "涨停", "跌停"]
|
|
72
|
+
|
|
73
|
+
# 多资产关键词
|
|
74
|
+
multi_asset_keywords = ["配置", "组合", "分散", "风险", "收益", "再平衡",
|
|
75
|
+
"仓位", "持仓", "资产配置"]
|
|
76
|
+
|
|
77
|
+
scores = {"macro": 0, "equity": 0, "multi_asset": 0}
|
|
78
|
+
|
|
79
|
+
for kw in macro_keywords:
|
|
80
|
+
if kw in query_lower:
|
|
81
|
+
scores["macro"] += 1
|
|
82
|
+
|
|
83
|
+
for kw in equity_keywords:
|
|
84
|
+
if kw in query_lower:
|
|
85
|
+
scores["equity"] += 1
|
|
86
|
+
|
|
87
|
+
for kw in multi_asset_keywords:
|
|
88
|
+
if kw in query_lower:
|
|
89
|
+
scores["multi_asset"] += 1
|
|
90
|
+
|
|
91
|
+
max_score = max(scores.values())
|
|
92
|
+
if max_score == 0:
|
|
93
|
+
return "macro" # 默认宏观
|
|
94
|
+
|
|
95
|
+
for intent, score in scores.items():
|
|
96
|
+
if score == max_score:
|
|
97
|
+
return intent
|
|
98
|
+
|
|
99
|
+
return "macro"
|
|
100
|
+
|
|
101
|
+
async def _comprehensive_analysis(self, query: str) -> str:
|
|
102
|
+
"""综合分析"""
|
|
103
|
+
prompt = f"""请对以下主题进行全面综合分析:
|
|
104
|
+
|
|
105
|
+
主题:{query}
|
|
106
|
+
|
|
107
|
+
请从以下维度进行分析:
|
|
108
|
+
1. 宏观背景
|
|
109
|
+
2. 市场现状
|
|
110
|
+
3. 关键因素
|
|
111
|
+
4. 风险提示
|
|
112
|
+
5. 投资建议
|
|
113
|
+
"""
|
|
114
|
+
return await self.brain.analyze(prompt, framework="综合分析框架")
|
|
115
|
+
|
|
116
|
+
def _help(self) -> str:
|
|
117
|
+
"""帮助信息"""
|
|
118
|
+
return """
|
|
119
|
+
/analyze - 综合分析命令
|
|
120
|
+
|
|
121
|
+
用法:
|
|
122
|
+
/analyze <查询内容>
|
|
123
|
+
|
|
124
|
+
示例:
|
|
125
|
+
/analyze A股当前走势
|
|
126
|
+
/analyze 茅台投资价值
|
|
127
|
+
/analyze 黄金避险情绪
|
|
128
|
+
/analyze 当前宏观经济形势
|
|
129
|
+
|
|
130
|
+
系统会自动识别查询意图并调用相应的分析师Agent。
|
|
131
|
+
"""
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""
|
|
2
|
+
/macro 命令 - 宏观分析
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from src.agents.macro import MacroAgent
|
|
7
|
+
from src.brain import Brain
|
|
8
|
+
from src.mcp.registry import MCPRegistry
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MacroCommand:
|
|
12
|
+
"""
|
|
13
|
+
宏观分析命令处理器
|
|
14
|
+
|
|
15
|
+
用法:
|
|
16
|
+
/macro CPI走势
|
|
17
|
+
/macro LPR利率
|
|
18
|
+
/macro 美联储政策
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, brain: Brain, mcp: MCPRegistry):
|
|
22
|
+
self.brain = brain
|
|
23
|
+
self.mcp = mcp
|
|
24
|
+
self.agent = MacroAgent(brain, mcp)
|
|
25
|
+
|
|
26
|
+
async def execute(self, args: str) -> str:
|
|
27
|
+
"""
|
|
28
|
+
执行宏观分析
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
args: 分析查询
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
分析结果
|
|
35
|
+
"""
|
|
36
|
+
if not args:
|
|
37
|
+
return self._help()
|
|
38
|
+
|
|
39
|
+
# 解析查询,提取指标
|
|
40
|
+
indicators = self._extract_indicators(args)
|
|
41
|
+
|
|
42
|
+
return await self.agent.process(
|
|
43
|
+
args,
|
|
44
|
+
indicators=indicators if indicators else None
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
def _extract_indicators(self, query: str) -> list:
|
|
48
|
+
"""从查询中提取宏观指标"""
|
|
49
|
+
indicator_map = {
|
|
50
|
+
"gdp": "GDP",
|
|
51
|
+
"国内生产总值": "GDP",
|
|
52
|
+
"cpi": "CPI",
|
|
53
|
+
"物价": "CPI",
|
|
54
|
+
"通胀": "CPI",
|
|
55
|
+
"ppi": "PPI",
|
|
56
|
+
"生产物价": "PPI",
|
|
57
|
+
"pmi": "PMI",
|
|
58
|
+
"采购经理": "PMI",
|
|
59
|
+
"社融": "社融",
|
|
60
|
+
"社会融资": "社融",
|
|
61
|
+
"m2": "M2",
|
|
62
|
+
"货币": "M2",
|
|
63
|
+
"lpr": "LPR",
|
|
64
|
+
"利率": "LPR",
|
|
65
|
+
"汇率": "汇率",
|
|
66
|
+
"人民币": "汇率",
|
|
67
|
+
"美元": "汇率",
|
|
68
|
+
"出口": "出口",
|
|
69
|
+
"进口": "进口",
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
query_lower = query.lower()
|
|
73
|
+
found = []
|
|
74
|
+
|
|
75
|
+
for keyword, indicator in indicator_map.items():
|
|
76
|
+
if keyword in query_lower and indicator not in found:
|
|
77
|
+
found.append(indicator)
|
|
78
|
+
|
|
79
|
+
return found
|
|
80
|
+
|
|
81
|
+
def _help(self) -> str:
|
|
82
|
+
"""帮助信息"""
|
|
83
|
+
return """
|
|
84
|
+
/macro - 宏观分析命令
|
|
85
|
+
|
|
86
|
+
用法:
|
|
87
|
+
/macro <查询内容>
|
|
88
|
+
|
|
89
|
+
示例:
|
|
90
|
+
/macro CPI走势
|
|
91
|
+
/macro PPI同比环比
|
|
92
|
+
/macro 制造业PMI
|
|
93
|
+
/macro LPR利率
|
|
94
|
+
/macro 人民币汇率
|
|
95
|
+
/macro 社融数据
|
|
96
|
+
/macro 美联储加息
|
|
97
|
+
|
|
98
|
+
支持的指标:
|
|
99
|
+
GDP, CPI, PPI, PMI, 社融, M2, LPR, 汇率, 出口, 进口
|
|
100
|
+
"""
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"""
|
|
2
|
+
/memo 命令 - 纪要管理
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Optional, List
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
import json
|
|
9
|
+
from src.brain import Brain
|
|
10
|
+
from src.mcp.registry import MCPRegistry
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MemoCommand:
|
|
14
|
+
"""
|
|
15
|
+
纪要管理命令处理器
|
|
16
|
+
|
|
17
|
+
用法:
|
|
18
|
+
/memo 记录今天的会议
|
|
19
|
+
/memo 列表
|
|
20
|
+
/memo 查看 20240101
|
|
21
|
+
/memo 搜索 茅台
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, brain: Brain, mcp: MCPRegistry):
|
|
25
|
+
self.brain = brain
|
|
26
|
+
self.mcp = mcp
|
|
27
|
+
self.memos_dir = Path("~/.openclaw-agent-06/workspace/erlangshen/knowledge/memos").expanduser()
|
|
28
|
+
self.memos_dir.mkdir(parents=True, exist_ok=True)
|
|
29
|
+
|
|
30
|
+
async def execute(self, args: str) -> str:
|
|
31
|
+
"""
|
|
32
|
+
执行纪要操作
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
args: 操作类型和内容
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
操作结果
|
|
39
|
+
"""
|
|
40
|
+
if not args:
|
|
41
|
+
return self._help()
|
|
42
|
+
|
|
43
|
+
args = args.strip()
|
|
44
|
+
parts = args.split(maxsplit=1)
|
|
45
|
+
action = parts[0]
|
|
46
|
+
content = parts[1] if len(parts) > 1 else ""
|
|
47
|
+
|
|
48
|
+
if action in ["记", "记录", "add", "create"]:
|
|
49
|
+
return await self._create_memo(content)
|
|
50
|
+
elif action in ["列表", "list"]:
|
|
51
|
+
return self._list_memos()
|
|
52
|
+
elif action in ["查看", "show", "read"]:
|
|
53
|
+
return await self._read_memo(content)
|
|
54
|
+
elif action in ["搜索", "search"]:
|
|
55
|
+
return await self._search_memos(content)
|
|
56
|
+
elif action in ["删除", "delete"]:
|
|
57
|
+
return self._delete_memo(content)
|
|
58
|
+
else:
|
|
59
|
+
# 默认为记录
|
|
60
|
+
return await self._create_memo(args)
|
|
61
|
+
|
|
62
|
+
async def _create_memo(self, content: str) -> str:
|
|
63
|
+
"""创建纪要"""
|
|
64
|
+
if not content:
|
|
65
|
+
return "请提供纪要内容"
|
|
66
|
+
|
|
67
|
+
# 生成文件名
|
|
68
|
+
date_str = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
69
|
+
filename = f"{date_str}.md"
|
|
70
|
+
filepath = self.memos_dir / filename
|
|
71
|
+
|
|
72
|
+
# 构建纪要内容
|
|
73
|
+
memo_content = f"""# 纪要 - {datetime.now().strftime("%Y年%m月%d日 %H:%M")}
|
|
74
|
+
|
|
75
|
+
## 内容
|
|
76
|
+
|
|
77
|
+
{content}
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
*由二郎神自动生成*
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
# 保存
|
|
84
|
+
with open(filepath, "w", encoding="utf-8") as f:
|
|
85
|
+
f.write(memo_content)
|
|
86
|
+
|
|
87
|
+
return f"✅ 纪要已保存: {filepath.name}"
|
|
88
|
+
|
|
89
|
+
def _list_memos(self) -> str:
|
|
90
|
+
"""列出所有纪要"""
|
|
91
|
+
memos = list(self.memos_dir.glob("*.md"))
|
|
92
|
+
|
|
93
|
+
if not memos:
|
|
94
|
+
return "暂无纪要"
|
|
95
|
+
|
|
96
|
+
memos.sort(key=lambda x: x.stem, reverse=True)
|
|
97
|
+
|
|
98
|
+
output = f"📝 共 {len(memos)} 条纪要:\n\n"
|
|
99
|
+
|
|
100
|
+
for memo in memos[:20]: # 最多显示20条
|
|
101
|
+
try:
|
|
102
|
+
content = memo.read_text(encoding="utf-8")
|
|
103
|
+
# 获取标题
|
|
104
|
+
title_line = content.split("\n")[0].replace("#", "").strip()
|
|
105
|
+
# 获取前50字符
|
|
106
|
+
preview = content[content.find("## 内容"):].replace("## 内容", "").strip()[:50]
|
|
107
|
+
|
|
108
|
+
date_str = memo.stem[:8]
|
|
109
|
+
date_formatted = f"{date_str[:4]}-{date_str[4:6]}-{date_str[6:8]}"
|
|
110
|
+
|
|
111
|
+
output += f"- **{date_formatted}** {title_line}\n"
|
|
112
|
+
output += f" {preview}...\n\n"
|
|
113
|
+
except Exception:
|
|
114
|
+
continue
|
|
115
|
+
|
|
116
|
+
if len(memos) > 20:
|
|
117
|
+
output += f"\n... 还有 {len(memos) - 20} 条纪要"
|
|
118
|
+
|
|
119
|
+
return output
|
|
120
|
+
|
|
121
|
+
async def _read_memo(self, identifier: str) -> str:
|
|
122
|
+
"""读取指定纪要"""
|
|
123
|
+
if not identifier:
|
|
124
|
+
return "请提供纪要标识"
|
|
125
|
+
|
|
126
|
+
# 尝试按日期或文件名查找
|
|
127
|
+
if identifier.isdigit() and len(identifier) == 8:
|
|
128
|
+
# 按日期查找
|
|
129
|
+
pattern = f"{identifier}*"
|
|
130
|
+
matches = list(self.memos_dir.glob(f"{pattern}.md"))
|
|
131
|
+
else:
|
|
132
|
+
# 按文件名或内容搜索
|
|
133
|
+
matches = list(self.memos_dir.glob("*.md"))
|
|
134
|
+
matches = [m for m in matches if identifier in m.stem or identifier in m.read_text()]
|
|
135
|
+
|
|
136
|
+
if not matches:
|
|
137
|
+
return f"未找到纪要: {identifier}"
|
|
138
|
+
|
|
139
|
+
# 返回最新的
|
|
140
|
+
memo = sorted(matches, key=lambda x: x.stem, reverse=True)[0]
|
|
141
|
+
content = memo.read_text(encoding="utf-8")
|
|
142
|
+
|
|
143
|
+
return f"📝 **{memo.stem}**\n\n{content}"
|
|
144
|
+
|
|
145
|
+
async def _search_memos(self, keyword: str) -> str:
|
|
146
|
+
"""搜索纪要"""
|
|
147
|
+
if not keyword:
|
|
148
|
+
return "请提供搜索关键词"
|
|
149
|
+
|
|
150
|
+
matches = []
|
|
151
|
+
|
|
152
|
+
for memo in self.memos_dir.glob("*.md"):
|
|
153
|
+
try:
|
|
154
|
+
content = memo.read_text(encoding="utf-8")
|
|
155
|
+
if keyword.lower() in content.lower():
|
|
156
|
+
matches.append({
|
|
157
|
+
"file": memo,
|
|
158
|
+
"content": content[:200]
|
|
159
|
+
})
|
|
160
|
+
except Exception:
|
|
161
|
+
continue
|
|
162
|
+
|
|
163
|
+
if not matches:
|
|
164
|
+
return f"未找到包含'{keyword}'的纪要"
|
|
165
|
+
|
|
166
|
+
output = f"🔍 找到 {len(matches)} 条相关纪要:\n\n"
|
|
167
|
+
|
|
168
|
+
for match in matches[:10]:
|
|
169
|
+
output += f"- **{match['file'].stem}**\n"
|
|
170
|
+
output += f" {match['content'][:100]}...\n\n"
|
|
171
|
+
|
|
172
|
+
return output
|
|
173
|
+
|
|
174
|
+
def _delete_memo(self, identifier: str) -> str:
|
|
175
|
+
"""删除纪要"""
|
|
176
|
+
if not identifier:
|
|
177
|
+
return "请提供要删除的纪要标识"
|
|
178
|
+
|
|
179
|
+
# 查找纪要
|
|
180
|
+
pattern = f"*{identifier}*" if identifier.isdigit() else f"*{identifier}*.md"
|
|
181
|
+
matches = list(self.memos_dir.glob(pattern))
|
|
182
|
+
|
|
183
|
+
if not matches:
|
|
184
|
+
return f"未找到纪要: {identifier}"
|
|
185
|
+
|
|
186
|
+
# 删除第一个匹配
|
|
187
|
+
memo = matches[0]
|
|
188
|
+
memo.unlink()
|
|
189
|
+
|
|
190
|
+
return f"✅ 已删除: {memo.name}"
|
|
191
|
+
|
|
192
|
+
def _help(self) -> str:
|
|
193
|
+
"""帮助信息"""
|
|
194
|
+
return """
|
|
195
|
+
/memo - 纪要管理命令
|
|
196
|
+
|
|
197
|
+
用法:
|
|
198
|
+
/memo <内容> - 快速记录
|
|
199
|
+
/memo 记录 <内容> - 记录新纪要
|
|
200
|
+
/memo 列表 - 查看所有纪要
|
|
201
|
+
/memo 查看 <标识> - 查看指定纪要
|
|
202
|
+
/memo 搜索 <关键词> - 搜索纪要
|
|
203
|
+
/memo 删除 <标识> - 删除纪要
|
|
204
|
+
|
|
205
|
+
示例:
|
|
206
|
+
/memo 今天讨论了量化策略
|
|
207
|
+
/memo 列表
|
|
208
|
+
/memo 查看 20240101
|
|
209
|
+
/memo 搜索 茅台
|
|
210
|
+
/memo 删除 20240101
|
|
211
|
+
|
|
212
|
+
说明:
|
|
213
|
+
- 纪要自动保存到本地知识库
|
|
214
|
+
- 支持按日期或关键词搜索
|
|
215
|
+
- 自动生成时间戳
|
|
216
|
+
"""
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""
|
|
2
|
+
/portfolio 命令 - 组合分析
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Optional, Dict, List
|
|
6
|
+
from src.agents.multi_asset import MultiAssetAgent
|
|
7
|
+
from src.brain import Brain
|
|
8
|
+
from src.mcp.registry import MCPRegistry
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PortfolioCommand:
|
|
12
|
+
"""
|
|
13
|
+
组合分析命令处理器
|
|
14
|
+
|
|
15
|
+
用法:
|
|
16
|
+
/portfolio 分析
|
|
17
|
+
/portfolio 再平衡
|
|
18
|
+
/portfolio 风险
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, brain: Brain, mcp: MCPRegistry):
|
|
22
|
+
self.brain = brain
|
|
23
|
+
self.mcp = mcp
|
|
24
|
+
self.agent = MultiAssetAgent(brain, mcp)
|
|
25
|
+
|
|
26
|
+
async def execute(self, args: str) -> str:
|
|
27
|
+
"""
|
|
28
|
+
执行组合分析
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
args: 分析类型
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
分析结果
|
|
35
|
+
"""
|
|
36
|
+
if not args:
|
|
37
|
+
return self._help()
|
|
38
|
+
|
|
39
|
+
args_lower = args.lower()
|
|
40
|
+
|
|
41
|
+
if "分析" in args or "查看" in args:
|
|
42
|
+
return await self._analyze_portfolio()
|
|
43
|
+
elif "再平衡" in args or "rebalance" in args_lower:
|
|
44
|
+
return await self._rebalance_suggestion()
|
|
45
|
+
elif "风险" in args:
|
|
46
|
+
return await self._risk_analysis()
|
|
47
|
+
elif "收益" in args or "业绩" in args:
|
|
48
|
+
return await self._performance_analysis()
|
|
49
|
+
else:
|
|
50
|
+
return await self._general_analysis(args)
|
|
51
|
+
|
|
52
|
+
async def _analyze_portfolio(self) -> str:
|
|
53
|
+
"""分析组合"""
|
|
54
|
+
# 默认组合配置
|
|
55
|
+
default_portfolio = {
|
|
56
|
+
"沪深300": 0.30,
|
|
57
|
+
"中证500": 0.15,
|
|
58
|
+
"恒生科技": 0.10,
|
|
59
|
+
"纳斯达克": 0.10,
|
|
60
|
+
"黄金": 0.10,
|
|
61
|
+
"债券": 0.15,
|
|
62
|
+
"现金": 0.10,
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return await self.agent.analyze_allocation(default_portfolio)
|
|
66
|
+
|
|
67
|
+
async def _rebalance_suggestion(self) -> str:
|
|
68
|
+
"""再平衡建议"""
|
|
69
|
+
current = {
|
|
70
|
+
"沪深300": 0.32,
|
|
71
|
+
"中证500": 0.14,
|
|
72
|
+
"恒生科技": 0.12,
|
|
73
|
+
"纳斯达克": 0.08,
|
|
74
|
+
"黄金": 0.08,
|
|
75
|
+
"债券": 0.16,
|
|
76
|
+
"现金": 0.10,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
target = {
|
|
80
|
+
"沪深300": 0.30,
|
|
81
|
+
"中证500": 0.15,
|
|
82
|
+
"恒生科技": 0.10,
|
|
83
|
+
"纳斯达克": 0.10,
|
|
84
|
+
"黄金": 0.10,
|
|
85
|
+
"债券": 0.15,
|
|
86
|
+
"现金": 0.10,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return await self.agent.rebalance_suggestion(current, target)
|
|
90
|
+
|
|
91
|
+
async def _risk_analysis(self) -> str:
|
|
92
|
+
"""风险分析"""
|
|
93
|
+
portfolio = {
|
|
94
|
+
"沪深300": 0.30,
|
|
95
|
+
"中证500": 0.15,
|
|
96
|
+
"恒生科技": 0.10,
|
|
97
|
+
"纳斯达克": 0.10,
|
|
98
|
+
"黄金": 0.10,
|
|
99
|
+
"债券": 0.15,
|
|
100
|
+
"现金": 0.10,
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return await self.agent.risk_analysis(portfolio)
|
|
104
|
+
|
|
105
|
+
async def _performance_analysis(self) -> str:
|
|
106
|
+
"""业绩分析"""
|
|
107
|
+
prompt = """请分析以下组合的历史业绩表现:
|
|
108
|
+
|
|
109
|
+
组合配置:
|
|
110
|
+
- 沪深300: 30%
|
|
111
|
+
- 中证500: 15%
|
|
112
|
+
- 恒生科技: 10%
|
|
113
|
+
- 纳斯达克: 10%
|
|
114
|
+
- 黄金: 10%
|
|
115
|
+
- 债券: 15%
|
|
116
|
+
- 现金: 10%
|
|
117
|
+
|
|
118
|
+
请从以下维度进行分析:
|
|
119
|
+
1. 收益表现 (YTD, 1Y, 3Y)
|
|
120
|
+
2. 风险指标 (波动率, 最大回撤)
|
|
121
|
+
3. 风险调整收益 (夏普比率, 卡玛比率)
|
|
122
|
+
4. 业绩归因
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
return await self.brain.analyze(prompt, framework="业绩归因框架")
|
|
126
|
+
|
|
127
|
+
async def _general_analysis(self, args: str) -> str:
|
|
128
|
+
"""通用分析"""
|
|
129
|
+
return await self.brain.analyze(
|
|
130
|
+
f"关于组合管理的问题:{args}",
|
|
131
|
+
framework="多资产配置框架"
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
def _help(self) -> str:
|
|
135
|
+
"""帮助信息"""
|
|
136
|
+
return """
|
|
137
|
+
/portfolio - 组合分析命令
|
|
138
|
+
|
|
139
|
+
用法:
|
|
140
|
+
/portfolio 分析 - 分析当前组合配置
|
|
141
|
+
/portfolio 再平衡 - 提供再平衡建议
|
|
142
|
+
/portfolio 风险 - 组合风险分析
|
|
143
|
+
/portfolio 业绩 - 业绩表现分析
|
|
144
|
+
|
|
145
|
+
示例:
|
|
146
|
+
/portfolio 分析
|
|
147
|
+
/portfolio 再平衡
|
|
148
|
+
/portfolio 风险
|
|
149
|
+
/portfolio 业绩归因
|
|
150
|
+
|
|
151
|
+
说明:
|
|
152
|
+
系统使用默认的参考组合配置进行分析。
|
|
153
|
+
如需分析自定义组合,请提供具体的配置比例。
|
|
154
|
+
"""
|