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
package/src/config.py
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
"""
|
|
2
|
+
二郎神配置管理
|
|
3
|
+
"""
|
|
4
|
+
import os
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Optional, Dict, Any, List
|
|
8
|
+
from pydantic import BaseModel, Field
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Config(BaseModel):
|
|
12
|
+
"""二郎神配置"""
|
|
13
|
+
|
|
14
|
+
# ==================== LLM 配置 ====================
|
|
15
|
+
llm_provider: str = "openai"
|
|
16
|
+
llm_model: str = "gpt-4"
|
|
17
|
+
llm_api_key: Optional[str] = None
|
|
18
|
+
llm_base_url: Optional[str] = None
|
|
19
|
+
llm_temperature: float = 0.7
|
|
20
|
+
llm_max_tokens: int = 4096
|
|
21
|
+
|
|
22
|
+
# ==================== DeepSeek 专用配置 ====================
|
|
23
|
+
deepseek_api_key: Optional[str] = None
|
|
24
|
+
deepseek_model: str = "deepseek-chat"
|
|
25
|
+
|
|
26
|
+
# ==================== MCP 配置 ====================
|
|
27
|
+
mcp_enabled: bool = True
|
|
28
|
+
mcp_timeout: int = 30
|
|
29
|
+
|
|
30
|
+
# ==================== 数据库配置 ====================
|
|
31
|
+
db_host: str = "localhost"
|
|
32
|
+
db_port: int = 5432
|
|
33
|
+
db_name: str = "market"
|
|
34
|
+
db_user: str = "postgres"
|
|
35
|
+
db_password: Optional[str] = None
|
|
36
|
+
|
|
37
|
+
# ==================== 飞书配置 ====================
|
|
38
|
+
feishu_app_id: Optional[str] = None
|
|
39
|
+
feishu_app_secret: Optional[str] = None
|
|
40
|
+
|
|
41
|
+
# ==================== 知识库路径 ====================
|
|
42
|
+
knowledge_dir: str = "~/.openclaw-agent-06/workspace/erlangshen/knowledge"
|
|
43
|
+
|
|
44
|
+
# ==================== 日志配置 ====================
|
|
45
|
+
log_level: str = "INFO"
|
|
46
|
+
log_file: Optional[str] = None
|
|
47
|
+
|
|
48
|
+
# ==================== 搜索配置 ====================
|
|
49
|
+
search_provider: str = "duckduckgo" # duckduckgo, serpapi, minimax
|
|
50
|
+
search_language: str = "auto" # auto, zh, en
|
|
51
|
+
serpapi_key: Optional[str] = None # SerpAPI API Key
|
|
52
|
+
|
|
53
|
+
# ==================== 市场数据 API 配置 ====================
|
|
54
|
+
|
|
55
|
+
# Alpha Vantage (免费额度: 25次/天)
|
|
56
|
+
alpha_vantage_key: Optional[str] = None
|
|
57
|
+
|
|
58
|
+
# Twelve Data (免费额度: 800次/天)
|
|
59
|
+
twelve_data_key: Optional[str] = None
|
|
60
|
+
|
|
61
|
+
# Trading Economics (免费额度: 有限)
|
|
62
|
+
trading_economics_key: Optional[str] = None
|
|
63
|
+
|
|
64
|
+
# CoinMarketCap (免费额度: 有限)
|
|
65
|
+
coinmarketcap_key: Optional[str] = None
|
|
66
|
+
|
|
67
|
+
# FRED (美联储经济数据 - 免费,需要API Key)
|
|
68
|
+
fred_api_key: Optional[str] = None
|
|
69
|
+
|
|
70
|
+
# ==================== 缓存配置 ====================
|
|
71
|
+
cache_enabled: bool = True
|
|
72
|
+
cache_ttl: int = 300 # 默认缓存时间(秒)
|
|
73
|
+
cache_max_size: int = 1000 # 最大缓存条目数
|
|
74
|
+
|
|
75
|
+
# ==================== 代理配置 ====================
|
|
76
|
+
http_proxy: Optional[str] = None
|
|
77
|
+
https_proxy: Optional[str] = None
|
|
78
|
+
proxy_enabled: bool = False
|
|
79
|
+
|
|
80
|
+
# ==================== 请求配置 ====================
|
|
81
|
+
request_timeout: int = 30 # 请求超时(秒)
|
|
82
|
+
max_retries: int = 3 # 最大重试次数
|
|
83
|
+
user_agent: str = "二郎神/1.0"
|
|
84
|
+
|
|
85
|
+
# ==================== 工具启用配置 ====================
|
|
86
|
+
enabled_tools: List[str] = Field(
|
|
87
|
+
default_factory=lambda: [
|
|
88
|
+
"market",
|
|
89
|
+
"search",
|
|
90
|
+
"file",
|
|
91
|
+
]
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# 市场工具子选项
|
|
95
|
+
enable_stock: bool = True # 股票数据
|
|
96
|
+
enable_crypto: bool = True # 加密货币
|
|
97
|
+
enable_commodity: bool = True # 大宗商品
|
|
98
|
+
enable_forex: bool = True # 外汇
|
|
99
|
+
enable_macro: bool = True # 宏观数据
|
|
100
|
+
|
|
101
|
+
# 搜索工具子选项
|
|
102
|
+
enable_web_search: bool = True
|
|
103
|
+
enable_news_search: bool = True
|
|
104
|
+
enable_academic_search: bool = True
|
|
105
|
+
enable_company_search: bool = True
|
|
106
|
+
|
|
107
|
+
class Config:
|
|
108
|
+
extra = "allow"
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def get_config_path() -> Path:
|
|
112
|
+
"""获取配置路径"""
|
|
113
|
+
return Path("~/.openclaw-agent-06/workspace/erlangshen/.claude/settings.json").expanduser()
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def get_default_config() -> Config:
|
|
117
|
+
"""获取默认配置"""
|
|
118
|
+
return Config()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def load_config() -> Config:
|
|
122
|
+
"""加载配置"""
|
|
123
|
+
config_path = get_config_path()
|
|
124
|
+
|
|
125
|
+
if config_path.exists():
|
|
126
|
+
try:
|
|
127
|
+
with open(config_path, "r", encoding="utf-8") as f:
|
|
128
|
+
data = json.load(f)
|
|
129
|
+
return Config(**data)
|
|
130
|
+
except (json.JSONDecodeError, TypeError) as e:
|
|
131
|
+
print(f"Warning: Failed to load config: {e}")
|
|
132
|
+
return Config()
|
|
133
|
+
|
|
134
|
+
return Config()
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def save_config(config: Config) -> None:
|
|
138
|
+
"""保存配置"""
|
|
139
|
+
config_path = get_config_path()
|
|
140
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
141
|
+
|
|
142
|
+
with open(config_path, "w", encoding="utf-8") as f:
|
|
143
|
+
json.dump(config.model_dump(), f, indent=2, ensure_ascii=False)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def merge_config(base: Config, updates: Dict[str, Any]) -> Config:
|
|
147
|
+
"""
|
|
148
|
+
合并配置更新
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
base: 基础配置
|
|
152
|
+
updates: 更新字典
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
Config: 合并后的配置
|
|
156
|
+
"""
|
|
157
|
+
base_dict = base.model_dump()
|
|
158
|
+
|
|
159
|
+
# 递归合并
|
|
160
|
+
def deep_merge(base_dict: dict, update_dict: dict) -> dict:
|
|
161
|
+
result = base_dict.copy()
|
|
162
|
+
for key, value in update_dict.items():
|
|
163
|
+
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
|
|
164
|
+
result[key] = deep_merge(result[key], value)
|
|
165
|
+
else:
|
|
166
|
+
result[key] = value
|
|
167
|
+
return result
|
|
168
|
+
|
|
169
|
+
merged = deep_merge(base_dict, updates)
|
|
170
|
+
return Config(**merged)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
# ==================== 环境变量支持 ====================
|
|
174
|
+
|
|
175
|
+
def load_config_from_env() -> Dict[str, Any]:
|
|
176
|
+
"""从环境变量加载配置"""
|
|
177
|
+
updates = {}
|
|
178
|
+
|
|
179
|
+
# API Keys
|
|
180
|
+
if os.getenv("OPENAI_API_KEY"):
|
|
181
|
+
updates["llm_api_key"] = os.getenv("OPENAI_API_KEY")
|
|
182
|
+
if os.getenv("DEEPSEEK_API_KEY"):
|
|
183
|
+
updates["deepseek_api_key"] = os.getenv("DEEPSEEK_API_KEY")
|
|
184
|
+
if os.getenv("SERPAPI_KEY"):
|
|
185
|
+
updates["serpapi_key"] = os.getenv("SERPAPI_KEY")
|
|
186
|
+
if os.getenv("ALPHA_VANTAGE_KEY"):
|
|
187
|
+
updates["alpha_vantage_key"] = os.getenv("ALPHA_VANTAGE_KEY")
|
|
188
|
+
if os.getenv("FRED_API_KEY"):
|
|
189
|
+
updates["fred_api_key"] = os.getenv("FRED_API_KEY")
|
|
190
|
+
if os.getenv("COINMARKETCAP_KEY"):
|
|
191
|
+
updates["coinmarketcap_key"] = os.getenv("COINMARKETCAP_KEY")
|
|
192
|
+
|
|
193
|
+
# 飞书配置
|
|
194
|
+
if os.getenv("FEISHU_APP_ID"):
|
|
195
|
+
updates["feishu_app_id"] = os.getenv("FEISHU_APP_ID")
|
|
196
|
+
if os.getenv("FEISHU_APP_SECRET"):
|
|
197
|
+
updates["feishu_app_secret"] = os.getenv("FEISHU_APP_SECRET")
|
|
198
|
+
|
|
199
|
+
# 数据库配置
|
|
200
|
+
if os.getenv("DB_HOST"):
|
|
201
|
+
updates["db_host"] = os.getenv("DB_HOST")
|
|
202
|
+
if os.getenv("DB_PASSWORD"):
|
|
203
|
+
updates["db_password"] = os.getenv("DB_PASSWORD")
|
|
204
|
+
|
|
205
|
+
# 代理配置
|
|
206
|
+
if os.getenv("HTTP_PROXY"):
|
|
207
|
+
updates["http_proxy"] = os.getenv("HTTP_PROXY")
|
|
208
|
+
updates["proxy_enabled"] = True
|
|
209
|
+
if os.getenv("HTTPS_PROXY"):
|
|
210
|
+
updates["https_proxy"] = os.getenv("HTTPS_PROXY")
|
|
211
|
+
|
|
212
|
+
return updates
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
# ==================== 全局配置实例 ====================
|
|
216
|
+
|
|
217
|
+
_config: Optional[Config] = None
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def get_config() -> Config:
|
|
221
|
+
"""获取全局配置"""
|
|
222
|
+
global _config
|
|
223
|
+
if _config is None:
|
|
224
|
+
# 先从环境变量加载
|
|
225
|
+
env_updates = load_config_from_env()
|
|
226
|
+
base_config = load_config()
|
|
227
|
+
|
|
228
|
+
if env_updates:
|
|
229
|
+
_config = merge_config(base_config, env_updates)
|
|
230
|
+
else:
|
|
231
|
+
_config = base_config
|
|
232
|
+
|
|
233
|
+
return _config
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def update_config(**kwargs) -> Config:
|
|
237
|
+
"""更新配置"""
|
|
238
|
+
global _config
|
|
239
|
+
config = get_config()
|
|
240
|
+
|
|
241
|
+
for key, value in kwargs.items():
|
|
242
|
+
if hasattr(config, key):
|
|
243
|
+
setattr(config, key, value)
|
|
244
|
+
|
|
245
|
+
save_config(config)
|
|
246
|
+
return config
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def reset_config() -> None:
|
|
250
|
+
"""重置配置"""
|
|
251
|
+
global _config
|
|
252
|
+
_config = None
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
# ==================== 配置验证 ====================
|
|
256
|
+
|
|
257
|
+
def validate_config(config: Config) -> List[str]:
|
|
258
|
+
"""
|
|
259
|
+
验证配置
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
config: 配置对象
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
List[str]: 警告列表
|
|
266
|
+
"""
|
|
267
|
+
warnings = []
|
|
268
|
+
|
|
269
|
+
# 检查 API Keys
|
|
270
|
+
if not config.llm_api_key and not config.deepseek_api_key:
|
|
271
|
+
warnings.append("未配置 LLM API Key,请设置 openai_api_key 或 deepseek_api_key")
|
|
272
|
+
|
|
273
|
+
if not config.serpapi_key:
|
|
274
|
+
warnings.append("未配置 SerpAPI Key,部分搜索功能可能受限 (仍可使用 DuckDuckGo)")
|
|
275
|
+
|
|
276
|
+
if not config.fred_api_key:
|
|
277
|
+
warnings.append("未配置 FRED API Key,宏观数据功能可能受限")
|
|
278
|
+
|
|
279
|
+
# 检查代理
|
|
280
|
+
if config.proxy_enabled and not (config.http_proxy or config.https_proxy):
|
|
281
|
+
warnings.append("启用了代理但未配置代理地址")
|
|
282
|
+
|
|
283
|
+
# 检查缓存
|
|
284
|
+
if config.cache_ttl < 60:
|
|
285
|
+
warnings.append("缓存 TTL 太短 (<60秒),可能导致频繁请求")
|
|
286
|
+
|
|
287
|
+
return warnings
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
# ==================== 常用配置模板 ====================
|
|
291
|
+
|
|
292
|
+
CONFIG_TEMPLATES = {
|
|
293
|
+
"development": {
|
|
294
|
+
"log_level": "DEBUG",
|
|
295
|
+
"cache_ttl": 60,
|
|
296
|
+
},
|
|
297
|
+
"production": {
|
|
298
|
+
"log_level": "INFO",
|
|
299
|
+
"cache_ttl": 300,
|
|
300
|
+
"cache_max_size": 5000,
|
|
301
|
+
},
|
|
302
|
+
"testing": {
|
|
303
|
+
"log_level": "WARNING",
|
|
304
|
+
"cache_enabled": False,
|
|
305
|
+
},
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def apply_template(name: str) -> Config:
|
|
310
|
+
"""
|
|
311
|
+
应用配置模板
|
|
312
|
+
|
|
313
|
+
Args:
|
|
314
|
+
name: 模板名称 (development, production, testing)
|
|
315
|
+
|
|
316
|
+
Returns:
|
|
317
|
+
Config: 应用模板后的配置
|
|
318
|
+
"""
|
|
319
|
+
if name not in CONFIG_TEMPLATES:
|
|
320
|
+
raise ValueError(f"Unknown template: {name}")
|
|
321
|
+
|
|
322
|
+
config = get_config()
|
|
323
|
+
merged = merge_config(config, CONFIG_TEMPLATES[name])
|
|
324
|
+
save_config(merged)
|
|
325
|
+
global _config
|
|
326
|
+
_config = merged
|
|
327
|
+
return merged
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Core engines: Brain, Cerebellum, Memory, Knowledge"""
|