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.
Files changed (93) hide show
  1. package/.claude/agents/equity-agent.md +26 -0
  2. package/.claude/agents/macro-agent.md +25 -0
  3. package/.claude/commands/analyze.md +40 -0
  4. package/.claude/commands/macro.md +29 -0
  5. package/.claude/settings.json +12 -0
  6. package/CODEX_GOAL.md +46 -0
  7. package/README.md +206 -0
  8. package/bin/cli.js +67 -0
  9. package/bin/erlangshen +2 -0
  10. package/bin/xiaoergod +2 -0
  11. package/frontend/index.html +700 -0
  12. package/knowledge/crypto_guide.md +147 -0
  13. package/knowledge/economic_indicators.md +125 -0
  14. package/knowledge/financial_glossary.md +148 -0
  15. package/knowledge/first_principles.md +50 -0
  16. package/knowledge/first_principles_deep.md +115 -0
  17. package/knowledge/global_markets.md +173 -0
  18. package/knowledge/insights.md +141 -0
  19. package/knowledge/market_basics.md +116 -0
  20. package/knowledge/memos/session_20260513_003616.json +6 -0
  21. package/knowledge/memos/session_20260513_003822.json +6 -0
  22. package/knowledge/risk_management.md +151 -0
  23. package/knowledge/team_context.md +42 -0
  24. package/knowledge/trading_strategies.md +114 -0
  25. package/package.json +42 -0
  26. package/requirements.txt +14 -0
  27. package/scripts/postinstall.js +188 -0
  28. package/scripts/preuninstall.js +22 -0
  29. package/src/__init__.py +4 -0
  30. package/src/__pycache__/__init__.cpython-313.pyc +0 -0
  31. package/src/agents/__init__.py +3 -0
  32. package/src/agents/base.py +103 -0
  33. package/src/agents/base_agent.py +86 -0
  34. package/src/agents/equity.py +136 -0
  35. package/src/agents/equity_agent.py +91 -0
  36. package/src/agents/erlang.py +165 -0
  37. package/src/agents/macro.py +137 -0
  38. package/src/agents/macro_agent.py +81 -0
  39. package/src/agents/multi_asset.py +147 -0
  40. package/src/agents/multi_asset_agent.py +87 -0
  41. package/src/api/__init__.py +1 -0
  42. package/src/api/__pycache__/__init__.cpython-313.pyc +0 -0
  43. package/src/api/__pycache__/server.cpython-313.pyc +0 -0
  44. package/src/api/cli.py +435 -0
  45. package/src/api/cli_enhanced.py +537 -0
  46. package/src/api/server.py +266 -0
  47. package/src/brain.py +200 -0
  48. package/src/cli.py +153 -0
  49. package/src/commands/__init__.py +3 -0
  50. package/src/commands/analyze.py +131 -0
  51. package/src/commands/macro.py +100 -0
  52. package/src/commands/memo.py +216 -0
  53. package/src/commands/portfolio.py +154 -0
  54. package/src/commands/report.py +228 -0
  55. package/src/commands/risk.py +183 -0
  56. package/src/commands/search.py +183 -0
  57. package/src/commands/stock.py +124 -0
  58. package/src/config.py +327 -0
  59. package/src/core/__init__.py +1 -0
  60. package/src/core/brain.py +645 -0
  61. package/src/core/cerebellum.py +175 -0
  62. package/src/core/investment_universe.py +423 -0
  63. package/src/core/knowledge.py +207 -0
  64. package/src/core/memory.py +115 -0
  65. package/src/hooks/__init__.py +3 -0
  66. package/src/hooks/session_end.py +57 -0
  67. package/src/hooks/session_start.py +75 -0
  68. package/src/knowledge/__init__.py +1 -0
  69. package/src/mcp/__init__.py +3 -0
  70. package/src/mcp/feishu.py +331 -0
  71. package/src/mcp/fund_tools.py +323 -0
  72. package/src/mcp/macro.py +452 -0
  73. package/src/mcp/market.py +331 -0
  74. package/src/mcp/registry.py +168 -0
  75. package/src/network/__init__.py +15 -0
  76. package/src/network/detector.py +125 -0
  77. package/src/network/proxy.py +199 -0
  78. package/src/network/router.py +103 -0
  79. package/src/prompts/__init__.py +1 -0
  80. package/src/prompts/analysis_framework.md +164 -0
  81. package/src/prompts/persona.md +65 -0
  82. package/src/prompts/report_template.md +144 -0
  83. package/src/skills/__init__.py +3 -0
  84. package/src/skills/framework.py +105 -0
  85. package/src/skills/templates.py +342 -0
  86. package/src/tools/__init__.py +1 -0
  87. package/src/tools/file_tools.py +209 -0
  88. package/src/tools/macro_tools.py +152 -0
  89. package/src/tools/market_tools.py +1172 -0
  90. package/src/tools/registry.py +398 -0
  91. package/src/tools/search_tools.py +777 -0
  92. package/tests/__init__.py +1 -0
  93. package/tests/test_erlangshen.py +140 -0
@@ -0,0 +1,175 @@
1
+ """
2
+ Cerebellum - 认知调度器
3
+ 协调大脑(Brain)和工具(Tools),负责任务编排、上下文管理、多跳推理
4
+ """
5
+ import json
6
+ from typing import Any, Optional
7
+ from loguru import logger
8
+ from pydantic import BaseModel, Field
9
+
10
+ from .brain import Brain, AnalysisResult
11
+ from .memory import Memory
12
+ from .knowledge import KnowledgeBase
13
+
14
+
15
+ class TaskStep(BaseModel):
16
+ """任务步骤"""
17
+ step_id: int
18
+ description: str
19
+ tool: Optional[str] = None
20
+ input_data: dict = Field(default_factory=dict)
21
+ output: Any = None
22
+
23
+
24
+ class TaskPlan(BaseModel):
25
+ """任务计划"""
26
+ task_id: str
27
+ query: str
28
+ steps: list[TaskStep] = Field(default_factory=list)
29
+ status: str = "pending" # pending, running, completed, failed
30
+
31
+
32
+ class Cerebellum:
33
+ """
34
+ 认知调度器 - 协调大脑和工具
35
+ 工作流程:
36
+ 1. 理解意图
37
+ 2. 规划任务
38
+ 3. 调用工具获取数据
39
+ 4. 大脑分析
40
+ 5. 生成回复
41
+ 6. 更新记忆
42
+ """
43
+
44
+ def __init__(
45
+ self,
46
+ brain: Optional[Brain] = None,
47
+ memory: Optional[Memory] = None,
48
+ knowledge: Optional[KnowledgeBase] = None,
49
+ ):
50
+ self.brain = brain or Brain()
51
+ self.memory = memory or Memory()
52
+ self.knowledge = knowledge or KnowledgeBase()
53
+ self._tool_registry: dict[str, Any] = {}
54
+
55
+ def register_tool(self, name: str, tool: Any) -> None:
56
+ """注册工具到调度器"""
57
+ self._tool_registry[name] = tool
58
+ logger.info(f"Registered tool: {name}")
59
+
60
+ async def _understand_intent(self, query: str) -> dict:
61
+ """理解用户意图,返回意图结构"""
62
+ prompt = f"""分析以下用户查询的意图:
63
+
64
+ 查询:「{query}」
65
+
66
+ 请返回JSON格式:
67
+ {{
68
+ "intent": "main intent category",
69
+ "sub_intent": "specific sub-intent",
70
+ "entities": ["key entities mentioned"],
71
+ "required_tools": ["needed tools to fulfill query"],
72
+ "complexity": "low/medium/high"
73
+ }}
74
+ """
75
+ try:
76
+ response = await self.brain.think(prompt)
77
+ # 尝试解析JSON
78
+ for line in response.split('\n'):
79
+ line = line.strip()
80
+ if line.startswith('{') and 'intent' in line:
81
+ start = response.find('{')
82
+ end = response.rfind('}') + 1
83
+ json_str = response[start:end]
84
+ return json.loads(json_str)
85
+ return {"intent": "general", "sub_intent": "query", "entities": [], "required_tools": [], "complexity": "low"}
86
+ except Exception as e:
87
+ logger.warning(f"Intent understanding failed: {e}")
88
+ return {"intent": "general", "sub_intent": "query", "entities": [], "required_tools": [], "complexity": "low"}
89
+
90
+ async def _plan_tasks(self, query: str, intent: dict) -> TaskPlan:
91
+ """规划任务步骤"""
92
+ task_id = f"task_{hash(query) % 100000}"
93
+ steps = []
94
+
95
+ # 根据意图生成步骤
96
+ if "analysis" in intent.get("intent", "").lower():
97
+ steps.append(TaskStep(step_id=1, description="获取相关数据", tool="search"))
98
+ steps.append(TaskStep(step_id=2, description="分析数据", tool=None))
99
+ steps.append(TaskStep(step_id=3, description="生成结论", tool=None))
100
+ elif "market" in intent.get("required_tools", []):
101
+ steps.append(TaskStep(step_id=1, description="查询行情数据", tool="market"))
102
+ steps.append(TaskStep(step_id=2, description="分析走势", tool=None))
103
+ elif "macro" in intent.get("required_tools", []):
104
+ steps.append(TaskStep(step_id=1, description="查询宏观数据", tool="macro"))
105
+ steps.append(TaskStep(step_id=2, description="分析经济形势", tool=None))
106
+ else:
107
+ steps.append(TaskStep(step_id=1, description="搜索相关信息", tool="search"))
108
+ steps.append(TaskStep(step_id=2, description="综合分析", tool=None))
109
+
110
+ return TaskPlan(task_id=task_id, query=query, steps=steps)
111
+
112
+ async def _execute_step(self, step: TaskStep) -> Any:
113
+ """执行单个任务步骤"""
114
+ if step.tool and step.tool in self._tool_registry:
115
+ tool = self._tool_registry[step.tool]
116
+ if hasattr(tool, "execute"):
117
+ return await tool.execute(**step.input_data)
118
+ elif callable(tool):
119
+ return await tool(**step.input_data)
120
+ return None
121
+
122
+ async def process(self, query: str) -> dict:
123
+ """
124
+ 处理用户查询的完整流程
125
+
126
+ Args:
127
+ query: 用户查询
128
+
129
+ Returns:
130
+ dict 包含结果、推理过程、置信度等
131
+ """
132
+ logger.info(f"Cerebellum processing: {query[:100]}")
133
+
134
+ # 1. 理解意图
135
+ intent = await self._understand_intent(query)
136
+
137
+ # 2. 规划任务
138
+ plan = await self._plan_tasks(query, intent)
139
+ plan.status = "running"
140
+
141
+ # 3. 执行任务步骤
142
+ all_data = {}
143
+ for step in plan.steps:
144
+ logger.info(f"Executing step {step.step_id}: {step.description}")
145
+ if step.tool:
146
+ step.output = await self._execute_step(step)
147
+ if step.output:
148
+ all_data[step.tool] = step.output
149
+ else:
150
+ # 分析步骤不需要工具
151
+ pass
152
+
153
+ # 4. 大脑分析
154
+ analysis = await self.brain.analyze(query, data=all_data)
155
+
156
+ # 5. 更新记忆
157
+ await self.memory.add_interaction(query, str(analysis.conclusion))
158
+
159
+ # 6. 返回结果
160
+ return {
161
+ "query": query,
162
+ "intent": intent,
163
+ "analysis": analysis.model_dump(),
164
+ "plan": {
165
+ "task_id": plan.task_id,
166
+ "steps": [
167
+ {"step_id": s.step_id, "description": s.description, "tool": s.tool}
168
+ for s in plan.steps
169
+ ],
170
+ },
171
+ }
172
+
173
+ async def query_knowledge(self, query: str, top_k: int = 5) -> list[dict]:
174
+ """查询知识库"""
175
+ return await self.knowledge.search(query, top_k)
@@ -0,0 +1,423 @@
1
+ """
2
+ Investment Universe - 全资产多策略能力图谱
3
+ 定义和管理所有支持的资产类别和策略类型
4
+ """
5
+ from typing import Dict, List, Optional, Any
6
+ from enum import Enum
7
+ from dataclasses import dataclass
8
+
9
+
10
+ # ============================================================
11
+ # 资产类别定义
12
+ # ============================================================
13
+
14
+ class AssetClass(str, Enum):
15
+ """资产类别枚举"""
16
+ # 权益类
17
+ A_STOCK = "a_stock" # A股
18
+ H_STOCK = "h_stock" # 港股
19
+ US_STOCK = "us_stock" # 美股
20
+ EUROPE_STOCK = "europe_stock" # 欧股
21
+ JAPAN_STOCK = "japan_stock" # 日股
22
+
23
+ # 债券类
24
+ GOV_BOND = "gov_bond" # 国债
25
+ CORPORATE_BOND = "corporate_bond" # 信用债
26
+ convertible_bond = "convertible_bond" # 可转债
27
+
28
+ # 商品类
29
+ GOLD = "gold" # 黄金
30
+ SILVER = "silver" # 白银
31
+ CRUDE_OIL = "crude_oil" # 原油
32
+ NATURAL_GAS = "natural_gas" # 天然气
33
+ COPPER = "copper" # 铜
34
+ AGRICULTURAL = "agricultural" # 农产品
35
+
36
+ # 外汇类
37
+ USD = "usd" # 美元
38
+ EUR = "eur" # 欧元
39
+ JPY = "jpy" # 日元
40
+ GBP = "gbp" # 英镑
41
+ CNY = "cny" # 人民币
42
+
43
+ # 数字资产
44
+ BTC = "btc" # 比特币
45
+ ETH = "eth" # 以太坊
46
+ CRYPTO = "crypto" # 加密货币
47
+
48
+ # 基金类
49
+ PUBLIC_FUND = "public_fund" # 公募基金
50
+ PRIVATE_FUND = "private_fund" # 私募基金
51
+ ETF = "etf" # ETF
52
+ INDEX_FUND = "index_fund" # 指数基金
53
+
54
+ # 期货类
55
+ STOCK_FUTURES = "stock_futures" # 股指期货
56
+ COMMODITY_FUTURES = "commodity_futures" # 商品期货
57
+ BOND_FUTURES = "bond_futures" # 国债期货
58
+
59
+
60
+ @dataclass
61
+ class AssetInfo:
62
+ """资产信息"""
63
+ code: AssetClass
64
+ name_cn: str
65
+ name_en: str
66
+ category: str # 权益/债券/商品/外汇/数字/基金/期货
67
+ data_source: str # 数据来源
68
+ keywords: List[str] # 识别关键词
69
+
70
+
71
+ # 资产类别映射
72
+ ASSET_REGISTRY: Dict[AssetClass, AssetInfo] = {
73
+ AssetClass.A_STOCK: AssetInfo(
74
+ code=AssetClass.A_STOCK,
75
+ name_cn="A股(沪深)",
76
+ name_en="China A-Shares",
77
+ category="权益",
78
+ data_source="remote_db",
79
+ keywords=["a股", "沪深", "上证", "深证", "沪市", "深市", "主板", "创业板", "科创板"],
80
+ ),
81
+ AssetClass.H_STOCK: AssetInfo(
82
+ code=AssetClass.H_STOCK,
83
+ name_cn="港股",
84
+ name_en="Hong Kong Stocks",
85
+ category="权益",
86
+ data_source="yahoo_finance",
87
+ keywords=["港股", "恒生", "hk", "h股", "香港上市"],
88
+ ),
89
+ AssetClass.US_STOCK: AssetInfo(
90
+ code=AssetClass.US_STOCK,
91
+ name_cn="美股",
92
+ name_en="US Stocks",
93
+ category="权益",
94
+ data_source="yahoo_finance",
95
+ keywords=["美股", "纳斯达克", "纽交所", "标普", "道琼斯", "nyse", "nasdaq", "sp500"],
96
+ ),
97
+ AssetClass.GOLD: AssetInfo(
98
+ code=AssetClass.GOLD,
99
+ name_cn="黄金",
100
+ name_en="Gold",
101
+ category="商品",
102
+ data_source="yahoo_finance",
103
+ keywords=["黄金", "gold", "xau", "金价", "贵金属"],
104
+ ),
105
+ AssetClass.CRUDE_OIL: AssetInfo(
106
+ code=AssetClass.CRUDE_OIL,
107
+ name_cn="原油",
108
+ name_en="Crude Oil",
109
+ category="商品",
110
+ data_source="yahoo_finance",
111
+ keywords=["原油", "石油", "oil", "wti", "brent", "布伦特"],
112
+ ),
113
+ AssetClass.GOV_BOND: AssetInfo(
114
+ code=AssetClass.GOV_BOND,
115
+ name_cn="国债",
116
+ name_en="Government Bond",
117
+ category="债券",
118
+ data_source="macro_tools",
119
+ keywords=["国债", "债券", "国开行", "国债期货", "treasury", "bond"],
120
+ ),
121
+ AssetClass.PUBLIC_FUND: AssetInfo(
122
+ code=AssetClass.PUBLIC_FUND,
123
+ name_cn="公募基金",
124
+ name_en="Public Fund",
125
+ category="基金",
126
+ data_source="remote_db",
127
+ keywords=["公募", "基金", "净值", "基金经理", "认购", "申购"],
128
+ ),
129
+ AssetClass.PRIVATE_FUND: AssetInfo(
130
+ code=AssetClass.PRIVATE_FUND,
131
+ name_cn="私募基金",
132
+ name_en="Private Fund",
133
+ category="基金",
134
+ data_source="remote_db",
135
+ keywords=["私募", "备案", "管理人", "托管", "阳光私募"],
136
+ ),
137
+ AssetClass.ETF: AssetInfo(
138
+ code=AssetClass.ETF,
139
+ name_cn="ETF",
140
+ name_en="ETF",
141
+ category="基金",
142
+ data_source="remote_db",
143
+ keywords=["etf", "交易型开放式指数基金", "指数etf", "行业etf"],
144
+ ),
145
+ AssetClass.BTC: AssetInfo(
146
+ code=AssetClass.BTC,
147
+ name_cn="比特币",
148
+ name_en="Bitcoin",
149
+ category="数字",
150
+ data_source="coingecko",
151
+ keywords=["比特币", "btc", "bitcoin", "数字货币", "加密货币"],
152
+ ),
153
+ AssetClass.ETH: AssetInfo(
154
+ code=AssetClass.ETH,
155
+ name_cn="以太坊",
156
+ name_en="Ethereum",
157
+ category="数字",
158
+ data_source="coingecko",
159
+ keywords=["以太坊", "eth", "ethereum"],
160
+ ),
161
+ AssetClass.STOCK_FUTURES: AssetInfo(
162
+ code=AssetClass.STOCK_FUTURES,
163
+ name_cn="股指期货",
164
+ name_en="Stock Index Futures",
165
+ category="期货",
166
+ data_source="yahoo_finance",
167
+ keywords=["股指期货", "if", "ih", "ic", "沪深300期货", "中证500期货"],
168
+ ),
169
+ }
170
+
171
+
172
+ # ============================================================
173
+ # 策略类型定义
174
+ # ============================================================
175
+
176
+ class StrategyType(str, Enum):
177
+ """策略类型枚举"""
178
+ MACRO_STRATEGY = "macro_strategy" # 宏观策略
179
+ CTA_QUANT = "cta_quant" # CTA量化
180
+ EQUITY_LONG_SHORT = "equity_long_short" # 股票多空
181
+ SUBJECTIVE_EQUITY = "subjective_equity" # 主观股票
182
+ PRIVATE_FOF = "private_fof" # 私募FOF
183
+ PUBLIC_FOF = "public_fof" # 公募FOF
184
+ RISK_PARITY = "risk_parity" # 风险平价
185
+ MOMENTUM = "momentum" # 趋势动量
186
+ REVERSAL = "reversal" # 均值回归
187
+ arbitrage = "arbitrage" # 套利
188
+ OPTIONS_HEDGE = "options_hedge" # 期权对冲
189
+ FIXED_INCOME = "fixed_income" # 固收
190
+
191
+
192
+ @dataclass
193
+ class StrategyInfo:
194
+ """策略信息"""
195
+ code: StrategyType
196
+ name_cn: str
197
+ name_en: str
198
+ category: str # 权益/债券/宏观/量化/组合
199
+ team_agent: str # 负责的Agent
200
+ keywords: List[str]
201
+
202
+
203
+ # 策略类型映射
204
+ STRATEGY_REGISTRY: Dict[StrategyType, StrategyInfo] = {
205
+ StrategyType.MACRO_STRATEGY: StrategyInfo(
206
+ code=StrategyType.MACRO_STRATEGY,
207
+ name_cn="宏观策略",
208
+ name_en="Macro Strategy",
209
+ category="宏观",
210
+ team_agent="agent-05",
211
+ keywords=["宏观", "大类资产配置", "经济周期", "货币政策", "财政政策", "利率", "通胀"],
212
+ ),
213
+ StrategyType.CTA_QUANT: StrategyInfo(
214
+ code=StrategyType.CTA_QUANT,
215
+ name_cn="CTA量化",
216
+ name_en="CTA Quant",
217
+ category="量化",
218
+ team_agent="agent-04",
219
+ keywords=["cta", "量化", "趋势跟踪", "商品期货", "动量", "趋势策略", "期货策略"],
220
+ ),
221
+ StrategyType.SUBJECTIVE_EQUITY: StrategyInfo(
222
+ code=StrategyType.SUBJECTIVE_EQUITY,
223
+ name_cn="主观股票",
224
+ name_en="Subjective Equity",
225
+ category="权益",
226
+ team_agent="agent-09",
227
+ keywords=["主观", "股票", "基本面", "价值投资", "成长投资", "个股研究"],
228
+ ),
229
+ StrategyType.PRIVATE_FOF: StrategyInfo(
230
+ code=StrategyType.PRIVATE_FOF,
231
+ name_cn="私募FOF",
232
+ name_en="Private Fund of Funds",
233
+ category="组合",
234
+ team_agent="agent-01",
235
+ keywords=["私募", "fof", "基金筛选", "尽调", "私募基金配置", "组合配置"],
236
+ ),
237
+ StrategyType.PUBLIC_FOF: StrategyInfo(
238
+ code=StrategyType.PUBLIC_FOF,
239
+ name_cn="公募FOF",
240
+ name_en="Public Fund of Funds",
241
+ category="组合",
242
+ team_agent="agent-02",
243
+ keywords=["公募", "fof", "基金配置", "养老基金", "稳健配置"],
244
+ ),
245
+ StrategyType.RISK_PARITY: StrategyInfo(
246
+ code=StrategyType.RISK_PARITY,
247
+ name_cn="风险平价",
248
+ name_en="Risk Parity",
249
+ category="组合",
250
+ team_agent="agent-05",
251
+ keywords=["风险平价", "风险预算", "波动率", "夏普比率", "资产配置"],
252
+ ),
253
+ StrategyType.MOMENTUM: StrategyInfo(
254
+ code=StrategyType.MOMENTUM,
255
+ name_cn="趋势动量",
256
+ name_en="Momentum",
257
+ category="量化",
258
+ team_agent="agent-04",
259
+ keywords=["动量", "趋势", "趋势跟踪", " momentum", "技术分析"],
260
+ ),
261
+ StrategyType.FIXED_INCOME: StrategyInfo(
262
+ code=StrategyType.FIXED_INCOME,
263
+ name_cn="固定收益",
264
+ name_en="Fixed Income",
265
+ category="债券",
266
+ team_agent="agent-05",
267
+ keywords=["固收", "债券", "信用债", "利率债", "中高收益", "债券基金"],
268
+ ),
269
+ }
270
+
271
+
272
+ # ============================================================
273
+ # 能力图谱查询
274
+ # ============================================================
275
+
276
+ class InvestmentUniverse:
277
+ """
278
+ 投资宇宙 - 全资产多策略能力图谱
279
+
280
+ 提供:
281
+ - 资产类别识别
282
+ - 策略类型识别
283
+ - 能力状态查询
284
+ - 数据源路由
285
+ """
286
+
287
+ def __init__(self):
288
+ self.assets = ASSET_REGISTRY
289
+ self.strategies = STRATEGY_REGISTRY
290
+
291
+ def identify_assets(self, query: str) -> List[AssetClass]:
292
+ """
293
+ 从查询中识别涉及的资产类别
294
+
295
+ Args:
296
+ query: 用户查询
297
+
298
+ Returns:
299
+ List[AssetClass] 匹配的资产类别列表
300
+ """
301
+ query_lower = query.lower()
302
+ matched = []
303
+
304
+ for asset_class, info in self.assets.items():
305
+ for keyword in info.keywords:
306
+ if keyword.lower() in query_lower:
307
+ if asset_class not in matched:
308
+ matched.append(asset_class)
309
+ break
310
+
311
+ return matched
312
+
313
+ def identify_strategies(self, query: str) -> List[StrategyType]:
314
+ """
315
+ 从查询中识别涉及的策略类型
316
+
317
+ Args:
318
+ query: 用户查询
319
+
320
+ Returns:
321
+ List[StrategyType] 匹配的策略类型列表
322
+ """
323
+ query_lower = query.lower()
324
+ matched = []
325
+
326
+ for strategy_type, info in self.strategies.items():
327
+ for keyword in info.keywords:
328
+ if keyword.lower() in query_lower:
329
+ if strategy_type not in matched:
330
+ matched.append(strategy_type)
331
+ break
332
+
333
+ return matched
334
+
335
+ def get_asset_info(self, asset: AssetClass) -> Optional[AssetInfo]:
336
+ """获取资产信息"""
337
+ return self.assets.get(asset)
338
+
339
+ def get_strategy_info(self, strategy: StrategyType) -> Optional[StrategyInfo]:
340
+ """获取策略信息"""
341
+ return self.strategies.get(strategy)
342
+
343
+ def get_data_source(self, asset: AssetClass) -> str:
344
+ """获取资产对应的数据源"""
345
+ info = self.assets.get(asset)
346
+ return info.data_source if info else "unknown"
347
+
348
+ def get_team_agent(self, strategy: StrategyType) -> str:
349
+ """获取策略对应的团队Agent"""
350
+ info = self.strategies.get(strategy)
351
+ return info.team_agent if info else "unknown"
352
+
353
+ def get_capability_state(self) -> dict:
354
+ """
355
+ 获取当前能力状态
356
+
357
+ Returns:
358
+ dict 包含已实现的资产类别和策略类型
359
+ """
360
+ return {
361
+ "assets": {
362
+ "total": len(self.assets),
363
+ "implemented": [
364
+ {
365
+ "code": a.value,
366
+ "name": info.name_cn,
367
+ "data_source": info.data_source,
368
+ }
369
+ for a, info in self.assets.items()
370
+ ],
371
+ },
372
+ "strategies": {
373
+ "total": len(self.strategies),
374
+ "implemented": [
375
+ {
376
+ "code": s.value,
377
+ "name": info.name_cn,
378
+ "team_agent": info.team_agent,
379
+ }
380
+ for s, info in self.strategies.items()
381
+ ],
382
+ },
383
+ }
384
+
385
+ def list_all_assets(self) -> List[Dict[str, str]]:
386
+ """列出所有资产类别"""
387
+ return [
388
+ {
389
+ "code": a.value,
390
+ "name_cn": info.name_cn,
391
+ "name_en": info.name_en,
392
+ "category": info.category,
393
+ }
394
+ for a, info in self.assets.items()
395
+ ]
396
+
397
+ def list_all_strategies(self) -> List[Dict[str, str]]:
398
+ """列出所有策略类型"""
399
+ return [
400
+ {
401
+ "code": s.value,
402
+ "name_cn": info.name_cn,
403
+ "name_en": info.name_en,
404
+ "category": info.category,
405
+ "team_agent": info.team_agent,
406
+ }
407
+ for s, info in self.strategies.items()
408
+ ]
409
+
410
+
411
+ # ============================================================
412
+ # 全局实例
413
+ # ============================================================
414
+
415
+ _universe: Optional[InvestmentUniverse] = None
416
+
417
+
418
+ def get_universe() -> InvestmentUniverse:
419
+ """获取投资宇宙实例"""
420
+ global _universe
421
+ if _universe is None:
422
+ _universe = InvestmentUniverse()
423
+ return _universe