docs(README): 更新项目说明文档,完善架构与启动指南
- 调整 CLAUDE.md 内容,增加使用指导和架构概览 - 补充微服务启动说明及单服务启动命令 - 明确 Gateway 服务器四阶段启动流程和职责划分 - 细化后端目录结构说明,补充主要文件职责描述 - 新增系统分层结构图,优化整体架构理解 - 更新 .gitignore,添加 runs 目录忽略规则 - 同步 .omc 相关状态文件,更新项目状态跟踪信息
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -54,10 +54,13 @@ outputs/
|
|||||||
/smoke_live_mock/
|
/smoke_live_mock/
|
||||||
|
|
||||||
# Local tooling state
|
# Local tooling state
|
||||||
/.omc/
|
.omc/
|
||||||
/.pydeps/
|
/.pydeps/
|
||||||
/referance/
|
/referance/
|
||||||
|
|
||||||
|
# Run outputs
|
||||||
|
/runs/
|
||||||
|
|
||||||
# Data files
|
# Data files
|
||||||
backend/data/ret_data/
|
backend/data/ret_data/
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"lastScanned": 1773938154948,
|
"lastScanned": 1774313111650,
|
||||||
"projectRoot": "/Users/cillin/workspeace/evotraders",
|
"projectRoot": "/Users/cillin/workspeace/evotraders",
|
||||||
"techStack": {
|
"techStack": {
|
||||||
"languages": [
|
"languages": [
|
||||||
@@ -11,14 +11,6 @@
|
|||||||
"markers": [
|
"markers": [
|
||||||
"pyproject.toml"
|
"pyproject.toml"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "C/C++",
|
|
||||||
"version": null,
|
|
||||||
"confidence": "high",
|
|
||||||
"markers": [
|
|
||||||
"Makefile"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"frameworks": [
|
"frameworks": [
|
||||||
@@ -32,8 +24,8 @@
|
|||||||
"runtime": null
|
"runtime": null
|
||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
"buildCommand": "make build",
|
"buildCommand": null,
|
||||||
"testCommand": "make test",
|
"testCommand": "pytest",
|
||||||
"lintCommand": "ruff check",
|
"lintCommand": "ruff check",
|
||||||
"devCommand": null,
|
"devCommand": null,
|
||||||
"scripts": {}
|
"scripts": {}
|
||||||
@@ -58,24 +50,13 @@
|
|||||||
},
|
},
|
||||||
"customNotes": [],
|
"customNotes": [],
|
||||||
"directoryMap": {
|
"directoryMap": {
|
||||||
"agent-service": {
|
|
||||||
"path": "agent-service",
|
|
||||||
"purpose": null,
|
|
||||||
"fileCount": 2,
|
|
||||||
"lastAccessed": 1773938154941,
|
|
||||||
"keyFiles": [
|
|
||||||
"Dockerfile",
|
|
||||||
"requirements.txt"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"backend": {
|
"backend": {
|
||||||
"path": "backend",
|
"path": "backend",
|
||||||
"purpose": null,
|
"purpose": null,
|
||||||
"fileCount": 5,
|
"fileCount": 4,
|
||||||
"lastAccessed": 1773938154941,
|
"lastAccessed": 1774313111639,
|
||||||
"keyFiles": [
|
"keyFiles": [
|
||||||
"__init__.py",
|
"__init__.py",
|
||||||
"app.py",
|
|
||||||
"cli.py",
|
"cli.py",
|
||||||
"gateway_server.py",
|
"gateway_server.py",
|
||||||
"main.py"
|
"main.py"
|
||||||
@@ -85,37 +66,41 @@
|
|||||||
"path": "backtest",
|
"path": "backtest",
|
||||||
"purpose": null,
|
"purpose": null,
|
||||||
"fileCount": 0,
|
"fileCount": 0,
|
||||||
"lastAccessed": 1773938154941,
|
"lastAccessed": 1774313111640,
|
||||||
"keyFiles": []
|
"keyFiles": []
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"path": "data",
|
"path": "data",
|
||||||
"purpose": "Data files",
|
"purpose": "Data files",
|
||||||
"fileCount": 1,
|
"fileCount": 3,
|
||||||
"lastAccessed": 1773938154941,
|
"lastAccessed": 1774313111640,
|
||||||
"keyFiles": [
|
"keyFiles": [
|
||||||
"market_research.db"
|
"market_research.db",
|
||||||
|
"market_research.db-shm",
|
||||||
|
"market_research.db-wal"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"deploy": {
|
"deploy": {
|
||||||
"path": "deploy",
|
"path": "deploy",
|
||||||
"purpose": null,
|
"purpose": null,
|
||||||
"fileCount": 0,
|
"fileCount": 0,
|
||||||
"lastAccessed": 1773938154942,
|
"lastAccessed": 1774313111640,
|
||||||
"keyFiles": []
|
"keyFiles": []
|
||||||
},
|
},
|
||||||
"docs": {
|
"docs": {
|
||||||
"path": "docs",
|
"path": "docs",
|
||||||
"purpose": "Documentation",
|
"purpose": "Documentation",
|
||||||
"fileCount": 0,
|
"fileCount": 1,
|
||||||
"lastAccessed": 1773938154942,
|
"lastAccessed": 1774313111641,
|
||||||
"keyFiles": []
|
"keyFiles": [
|
||||||
|
"compat-removal-plan.md"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"evotraders.egg-info": {
|
"evotraders.egg-info": {
|
||||||
"path": "evotraders.egg-info",
|
"path": "evotraders.egg-info",
|
||||||
"purpose": null,
|
"purpose": null,
|
||||||
"fileCount": 6,
|
"fileCount": 6,
|
||||||
"lastAccessed": 1773938154942,
|
"lastAccessed": 1774313111641,
|
||||||
"keyFiles": [
|
"keyFiles": [
|
||||||
"PKG-INFO",
|
"PKG-INFO",
|
||||||
"SOURCES.txt",
|
"SOURCES.txt",
|
||||||
@@ -128,7 +113,7 @@
|
|||||||
"path": "frontend",
|
"path": "frontend",
|
||||||
"purpose": null,
|
"purpose": null,
|
||||||
"fileCount": 13,
|
"fileCount": 13,
|
||||||
"lastAccessed": 1773938154942,
|
"lastAccessed": 1774313111641,
|
||||||
"keyFiles": [
|
"keyFiles": [
|
||||||
"README.md",
|
"README.md",
|
||||||
"components.json",
|
"components.json",
|
||||||
@@ -141,51 +126,41 @@
|
|||||||
"path": "live",
|
"path": "live",
|
||||||
"purpose": null,
|
"purpose": null,
|
||||||
"fileCount": 0,
|
"fileCount": 0,
|
||||||
"lastAccessed": 1773938154943,
|
"lastAccessed": 1774313111642,
|
||||||
"keyFiles": []
|
"keyFiles": []
|
||||||
},
|
},
|
||||||
"logs": {
|
"logs": {
|
||||||
"path": "logs",
|
"path": "logs",
|
||||||
"purpose": null,
|
"purpose": null,
|
||||||
"fileCount": 7,
|
"fileCount": 6,
|
||||||
"lastAccessed": 1773938154943,
|
"lastAccessed": 1774313111642,
|
||||||
"keyFiles": [
|
"keyFiles": [
|
||||||
"2026-03-16_00-48-03.log",
|
"2026-03-16_00-48-03.log",
|
||||||
"2026-03-18_23-17-29.log",
|
"2026-03-18_23-17-29.log",
|
||||||
"2026-03-18_23-17-30.2026-03-18_23-17-30_000801.log.zip",
|
|
||||||
"2026-03-18_23-17-30.log",
|
"2026-03-18_23-17-30.log",
|
||||||
"2026-03-19_00-18-04.log"
|
"2026-03-19_00-18-04.log",
|
||||||
]
|
"2026-03-19_00-34-21.log"
|
||||||
},
|
|
||||||
"news-service": {
|
|
||||||
"path": "news-service",
|
|
||||||
"purpose": null,
|
|
||||||
"fileCount": 3,
|
|
||||||
"lastAccessed": 1773938154943,
|
|
||||||
"keyFiles": [
|
|
||||||
"Dockerfile",
|
|
||||||
"requirements.txt"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"reference": {
|
"reference": {
|
||||||
"path": "reference",
|
"path": "reference",
|
||||||
"purpose": null,
|
"purpose": null,
|
||||||
"fileCount": 0,
|
"fileCount": 0,
|
||||||
"lastAccessed": 1773938154943,
|
"lastAccessed": 1774313111643,
|
||||||
"keyFiles": []
|
"keyFiles": []
|
||||||
},
|
},
|
||||||
"runs": {
|
"runs": {
|
||||||
"path": "runs",
|
"path": "runs",
|
||||||
"purpose": null,
|
"purpose": null,
|
||||||
"fileCount": 0,
|
"fileCount": 0,
|
||||||
"lastAccessed": 1773938154944,
|
"lastAccessed": 1774313111643,
|
||||||
"keyFiles": []
|
"keyFiles": []
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"path": "scripts",
|
"path": "scripts",
|
||||||
"purpose": "Build/utility scripts",
|
"purpose": "Build/utility scripts",
|
||||||
"fileCount": 1,
|
"fileCount": 1,
|
||||||
"lastAccessed": 1773938154944,
|
"lastAccessed": 1774313111644,
|
||||||
"keyFiles": [
|
"keyFiles": [
|
||||||
"run_prod.sh"
|
"run_prod.sh"
|
||||||
]
|
]
|
||||||
@@ -194,7 +169,7 @@
|
|||||||
"path": "services",
|
"path": "services",
|
||||||
"purpose": "Business logic services",
|
"purpose": "Business logic services",
|
||||||
"fileCount": 1,
|
"fileCount": 1,
|
||||||
"lastAccessed": 1773938154944,
|
"lastAccessed": 1774313111644,
|
||||||
"keyFiles": [
|
"keyFiles": [
|
||||||
"README.md"
|
"README.md"
|
||||||
]
|
]
|
||||||
@@ -203,43 +178,21 @@
|
|||||||
"path": "shared",
|
"path": "shared",
|
||||||
"purpose": null,
|
"purpose": null,
|
||||||
"fileCount": 0,
|
"fileCount": 0,
|
||||||
"lastAccessed": 1773938154944,
|
"lastAccessed": 1774313111644,
|
||||||
"keyFiles": []
|
"keyFiles": []
|
||||||
},
|
},
|
||||||
"trading-service": {
|
|
||||||
"path": "trading-service",
|
|
||||||
"purpose": null,
|
|
||||||
"fileCount": 4,
|
|
||||||
"lastAccessed": 1773938154944,
|
|
||||||
"keyFiles": [
|
|
||||||
"Dockerfile",
|
|
||||||
"README.md",
|
|
||||||
"requirements.txt"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"workspaces": {
|
"workspaces": {
|
||||||
"path": "workspaces",
|
"path": "workspaces",
|
||||||
"purpose": null,
|
"purpose": null,
|
||||||
"fileCount": 0,
|
"fileCount": 0,
|
||||||
"lastAccessed": 1773938154944,
|
"lastAccessed": 1774313111645,
|
||||||
"keyFiles": []
|
"keyFiles": []
|
||||||
},
|
},
|
||||||
"agent-service/src": {
|
|
||||||
"path": "agent-service/src",
|
|
||||||
"purpose": "Source code",
|
|
||||||
"fileCount": 5,
|
|
||||||
"lastAccessed": 1773938154944,
|
|
||||||
"keyFiles": [
|
|
||||||
"__init__.py",
|
|
||||||
"config.py",
|
|
||||||
"main.py"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"backend/api": {
|
"backend/api": {
|
||||||
"path": "backend/api",
|
"path": "backend/api",
|
||||||
"purpose": "API routes",
|
"purpose": "API routes",
|
||||||
"fileCount": 5,
|
"fileCount": 5,
|
||||||
"lastAccessed": 1773938154944,
|
"lastAccessed": 1774313111645,
|
||||||
"keyFiles": [
|
"keyFiles": [
|
||||||
"__init__.py",
|
"__init__.py",
|
||||||
"agents.py",
|
"agents.py",
|
||||||
@@ -250,7 +203,7 @@
|
|||||||
"path": "backend/config",
|
"path": "backend/config",
|
||||||
"purpose": "Configuration files",
|
"purpose": "Configuration files",
|
||||||
"fileCount": 6,
|
"fileCount": 6,
|
||||||
"lastAccessed": 1773938154944,
|
"lastAccessed": 1774313111646,
|
||||||
"keyFiles": [
|
"keyFiles": [
|
||||||
"__init__.py",
|
"__init__.py",
|
||||||
"agent_profiles.yaml",
|
"agent_profiles.yaml",
|
||||||
@@ -261,7 +214,7 @@
|
|||||||
"path": "backend/data",
|
"path": "backend/data",
|
||||||
"purpose": "Data files",
|
"purpose": "Data files",
|
||||||
"fileCount": 13,
|
"fileCount": 13,
|
||||||
"lastAccessed": 1773938154944,
|
"lastAccessed": 1774313111647,
|
||||||
"keyFiles": [
|
"keyFiles": [
|
||||||
"__init__.py",
|
"__init__.py",
|
||||||
"cache.py",
|
"cache.py",
|
||||||
@@ -272,7 +225,7 @@
|
|||||||
"path": "docs/assets",
|
"path": "docs/assets",
|
||||||
"purpose": "Static assets",
|
"purpose": "Static assets",
|
||||||
"fileCount": 5,
|
"fileCount": 5,
|
||||||
"lastAccessed": 1773938154944,
|
"lastAccessed": 1774313111647,
|
||||||
"keyFiles": [
|
"keyFiles": [
|
||||||
"dashboard.jpg",
|
"dashboard.jpg",
|
||||||
"evotraders_demo.gif",
|
"evotraders_demo.gif",
|
||||||
@@ -283,7 +236,7 @@
|
|||||||
"path": "frontend/dist",
|
"path": "frontend/dist",
|
||||||
"purpose": "Distribution/build output",
|
"purpose": "Distribution/build output",
|
||||||
"fileCount": 2,
|
"fileCount": 2,
|
||||||
"lastAccessed": 1773938154945,
|
"lastAccessed": 1774313111647,
|
||||||
"keyFiles": [
|
"keyFiles": [
|
||||||
"index.html",
|
"index.html",
|
||||||
"trading_logo.png"
|
"trading_logo.png"
|
||||||
@@ -293,331 +246,261 @@
|
|||||||
"path": "frontend/node_modules",
|
"path": "frontend/node_modules",
|
||||||
"purpose": "Dependencies",
|
"purpose": "Dependencies",
|
||||||
"fileCount": 1,
|
"fileCount": 1,
|
||||||
"lastAccessed": 1773938154947,
|
"lastAccessed": 1774313111650,
|
||||||
"keyFiles": []
|
"keyFiles": []
|
||||||
},
|
|
||||||
"news-service/src": {
|
|
||||||
"path": "news-service/src",
|
|
||||||
"purpose": "Source code",
|
|
||||||
"fileCount": 3,
|
|
||||||
"lastAccessed": 1773938154948,
|
|
||||||
"keyFiles": [
|
|
||||||
"__init__.py",
|
|
||||||
"config.py",
|
|
||||||
"main.py"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"trading-service/src": {
|
|
||||||
"path": "trading-service/src",
|
|
||||||
"purpose": "Source code",
|
|
||||||
"fileCount": 8,
|
|
||||||
"lastAccessed": 1773938154948,
|
|
||||||
"keyFiles": [
|
|
||||||
"__init__.py",
|
|
||||||
"config.py",
|
|
||||||
"main.py"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"hotPaths": [
|
"hotPaths": [
|
||||||
{
|
{
|
||||||
"path": "backend/agents/factory.py",
|
"path": "CLAUDE.md",
|
||||||
"accessCount": 17,
|
"accessCount": 15,
|
||||||
"lastAccessed": 1773939950376,
|
"lastAccessed": 1774342728155,
|
||||||
|
"type": "directory"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "frontend/src/App.jsx",
|
||||||
|
"accessCount": 10,
|
||||||
|
"lastAccessed": 1774339397617,
|
||||||
"type": "file"
|
"type": "file"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "backend",
|
"path": "frontend/src/hooks/useWebsocketSessionSync.js",
|
||||||
"accessCount": 16,
|
"accessCount": 4,
|
||||||
"lastAccessed": 1773940042371,
|
"lastAccessed": 1774313470024,
|
||||||
"type": "directory"
|
"type": "file"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "",
|
"path": "",
|
||||||
"accessCount": 13,
|
"accessCount": 4,
|
||||||
"lastAccessed": 1773939899611,
|
"lastAccessed": 1774339108220,
|
||||||
"type": "directory"
|
"type": "directory"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"path": "backend/main.py",
|
|
||||||
"accessCount": 7,
|
|
||||||
"lastAccessed": 1773939993951,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/gateway_server.py",
|
|
||||||
"accessCount": 7,
|
|
||||||
"lastAccessed": 1773940004402,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/services/news/main.py",
|
|
||||||
"accessCount": 5,
|
|
||||||
"lastAccessed": 1773938385662,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/core/pipeline.py",
|
|
||||||
"accessCount": 5,
|
|
||||||
"lastAccessed": 1773940024933,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/services/news/enrich/news_enricher.py",
|
|
||||||
"accessCount": 4,
|
|
||||||
"lastAccessed": 1773938508417,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "start-dev.sh",
|
|
||||||
"accessCount": 4,
|
|
||||||
"lastAccessed": 1773939259381,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "services/README.md",
|
|
||||||
"accessCount": 4,
|
|
||||||
"lastAccessed": 1773939281935,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/app.py",
|
|
||||||
"accessCount": 4,
|
|
||||||
"lastAccessed": 1773939648215,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/services/news/routes/news.py",
|
|
||||||
"accessCount": 3,
|
|
||||||
"lastAccessed": 1773938438928,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/services/news",
|
|
||||||
"accessCount": 3,
|
|
||||||
"lastAccessed": 1773938468730,
|
|
||||||
"type": "directory"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "frontend/src/config/constants.js",
|
|
||||||
"accessCount": 3,
|
|
||||||
"lastAccessed": 1773939204395,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"path": "backend/services/gateway.py",
|
"path": "backend/services/gateway.py",
|
||||||
"accessCount": 3,
|
"accessCount": 3,
|
||||||
"lastAccessed": 1773939672930,
|
"lastAccessed": 1774339389171,
|
||||||
"type": "file"
|
"type": "file"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "backend/core/__init__.py",
|
"path": "backend/main.py",
|
||||||
"accessCount": 3,
|
"accessCount": 3,
|
||||||
"lastAccessed": 1773939963627,
|
"lastAccessed": 1774342613364,
|
||||||
"type": "file"
|
"type": "file"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "backend/services/trading/main.py",
|
"path": "frontend/src/store/runtimeStore.js",
|
||||||
"accessCount": 2,
|
"accessCount": 2,
|
||||||
"lastAccessed": 1773938360736,
|
"lastAccessed": 1774317990919,
|
||||||
"type": "file"
|
"type": "file"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "backend/services/agents/main.py",
|
"path": "frontend/src/services/websocket.js",
|
||||||
"accessCount": 2,
|
"accessCount": 2,
|
||||||
"lastAccessed": 1773938361040,
|
"lastAccessed": 1774318009819,
|
||||||
"type": "file"
|
"type": "file"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "backend/services/trading/data/__init__.py",
|
"path": "backend/core/pipeline_runner.py",
|
||||||
"accessCount": 2,
|
"accessCount": 2,
|
||||||
"lastAccessed": 1773938402496,
|
"lastAccessed": 1774339367538,
|
||||||
"type": "file"
|
"type": "file"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "backend/services/news/explain/__init__.py",
|
"path": "backend/runtime/manager.py",
|
||||||
"accessCount": 2,
|
"accessCount": 2,
|
||||||
"lastAccessed": 1773938460019,
|
"lastAccessed": 1774339367572,
|
||||||
"type": "file"
|
"type": "file"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "backend/services/news/enrich/__init__.py",
|
"path": "frontend/src/store/marketStore.js",
|
||||||
"accessCount": 2,
|
|
||||||
"lastAccessed": 1773938465216,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/services/news/explain/range_explainer.py",
|
|
||||||
"accessCount": 2,
|
|
||||||
"lastAccessed": 1773938481152,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/services/news/enrich/llm_enricher.py",
|
|
||||||
"accessCount": 2,
|
|
||||||
"lastAccessed": 1773938499885,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "CLAUDE.md",
|
|
||||||
"accessCount": 2,
|
|
||||||
"lastAccessed": 1773939273598,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/agents/__init__.py",
|
|
||||||
"accessCount": 2,
|
|
||||||
"lastAccessed": 1773939883015,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/agents/agent_core.py",
|
|
||||||
"accessCount": 2,
|
|
||||||
"lastAccessed": 1773939886997,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "Makefile",
|
|
||||||
"accessCount": 1,
|
"accessCount": 1,
|
||||||
"lastAccessed": 1773938226307,
|
"lastAccessed": 1774313140483,
|
||||||
"type": "file"
|
"type": "file"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "docker-compose.yml",
|
"path": "frontend/src/hooks/useFeedProcessor.js",
|
||||||
"accessCount": 1,
|
"accessCount": 1,
|
||||||
"lastAccessed": 1773938226360,
|
"lastAccessed": 1774313148279,
|
||||||
"type": "file"
|
"type": "file"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "backend/services/news/shared/trading_client.py",
|
"path": "frontend/src/components/Header.jsx",
|
||||||
"accessCount": 1,
|
"accessCount": 1,
|
||||||
"lastAccessed": 1773938370618,
|
"lastAccessed": 1774313156696,
|
||||||
"type": "file"
|
"type": "file"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "backend/services/agents",
|
"path": "frontend/src/components/TraderView.jsx",
|
||||||
"accessCount": 1,
|
"accessCount": 1,
|
||||||
"lastAccessed": 1773938397772,
|
"lastAccessed": 1774313156753,
|
||||||
"type": "directory"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/services/trading",
|
|
||||||
"accessCount": 1,
|
|
||||||
"lastAccessed": 1773938397823,
|
|
||||||
"type": "directory"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/services",
|
|
||||||
"accessCount": 1,
|
|
||||||
"lastAccessed": 1773938405541,
|
|
||||||
"type": "directory"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/services/news/config.py",
|
|
||||||
"accessCount": 1,
|
|
||||||
"lastAccessed": 1773938638664,
|
|
||||||
"type": "file"
|
"type": "file"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "shared/client/news_client.py",
|
"path": "frontend/src/store/uiStore.js",
|
||||||
"accessCount": 1,
|
"accessCount": 1,
|
||||||
"lastAccessed": 1773938638715,
|
"lastAccessed": 1774313187460,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "frontend/src/store/portfolioStore.js",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774313187511,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "frontend/src/store/agentStore.js",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774313187573,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "frontend/src/hooks/useWebSocketConnection.js",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774313279414,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "frontend/src/hooks/useStockDataRequests.js",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774313319716,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "frontend/src/hooks/useAgentDataRequests.js",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774313347455,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "frontend/src/components/AppShell.jsx",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774313396331,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "start-dev.sh",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774317979859,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "backend/apps/agent_service.py",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774317984348,
|
||||||
"type": "file"
|
"type": "file"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "shared/client/trading_client.py",
|
"path": "shared/client/trading_client.py",
|
||||||
"accessCount": 1,
|
"accessCount": 1,
|
||||||
"lastAccessed": 1773938638770,
|
"lastAccessed": 1774317984365,
|
||||||
"type": "file"
|
"type": "file"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "backend/api",
|
"path": "backend/apps/trading_service.py",
|
||||||
"accessCount": 1,
|
"accessCount": 1,
|
||||||
"lastAccessed": 1773938669143,
|
"lastAccessed": 1774317984408,
|
||||||
"type": "directory"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "frontend",
|
|
||||||
"accessCount": 1,
|
|
||||||
"lastAccessed": 1773938669195,
|
|
||||||
"type": "directory"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": ".env.example",
|
|
||||||
"accessCount": 1,
|
|
||||||
"lastAccessed": 1773938849397,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "frontend/src/services/websocket.js",
|
|
||||||
"accessCount": 1,
|
|
||||||
"lastAccessed": 1773938849448,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "frontend/src/services/runtimeApi.js",
|
|
||||||
"accessCount": 1,
|
|
||||||
"lastAccessed": 1773938849500,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/services/agents/routes/websocket.py",
|
|
||||||
"accessCount": 1,
|
|
||||||
"lastAccessed": 1773939001692,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/services/agents/routes/agents.py",
|
|
||||||
"accessCount": 1,
|
|
||||||
"lastAccessed": 1773939016291,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/services/agents/routes/run.py",
|
|
||||||
"accessCount": 1,
|
|
||||||
"lastAccessed": 1773939016343,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/__init__.py",
|
|
||||||
"accessCount": 1,
|
|
||||||
"lastAccessed": 1773939648323,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/api/__init__.py",
|
|
||||||
"accessCount": 1,
|
|
||||||
"lastAccessed": 1773939658650,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/runtime/__init__.py",
|
|
||||||
"accessCount": 1,
|
|
||||||
"lastAccessed": 1773939658687,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/agents/base/evo_agent.py",
|
|
||||||
"accessCount": 1,
|
|
||||||
"lastAccessed": 1773939664916,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/agents/analyst.py",
|
|
||||||
"accessCount": 1,
|
|
||||||
"lastAccessed": 1773939664967,
|
|
||||||
"type": "file"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "backend/agents/base/hooks.py",
|
|
||||||
"accessCount": 1,
|
|
||||||
"lastAccessed": 1773939672727,
|
|
||||||
"type": "file"
|
"type": "file"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "pyproject.toml",
|
"path": "pyproject.toml",
|
||||||
"accessCount": 1,
|
"accessCount": 1,
|
||||||
"lastAccessed": 1773939672778,
|
"lastAccessed": 1774317990970,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "backend/agents/factory.py",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774318009867,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "backend/config/constants.py",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774318009922,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "backend/api/__init__.py",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774318009973,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "README.md",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774339107381,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "backend/runtime/registry.py",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774339380024,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "backend/runtime/session.py",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774339380084,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "backend/runtime/context.py",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774339380120,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "backend/runtime/agent_runtime.py",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774339380185,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "backend/process/supervisor.py",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774339389110,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "backend/core/pipeline.py",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774339389187,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "backend/process/models.py",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774339397557,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "backend/process/registry.py",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774339397577,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "backend/config/env_config.py",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774342678236,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "backend/config/data_config.py",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774342678253,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "frontend/env.template",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774342678290,
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "env.template",
|
||||||
|
"accessCount": 1,
|
||||||
|
"lastAccessed": 1774342678310,
|
||||||
"type": "file"
|
"type": "file"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"timestamp": "2026-03-19T16:36:52.471Z",
|
"timestamp": "2026-03-24T07:58:12.123Z",
|
||||||
"backgroundTasks": [],
|
"backgroundTasks": [],
|
||||||
"sessionStartTimestamp": "2026-03-19T16:36:42.224Z",
|
"sessionStartTimestamp": "2026-03-24T07:58:09.417Z",
|
||||||
"sessionId": "ef02339a-1eec-4c7a-95ac-c8cfa0b5067d"
|
"sessionId": "fda34772-7bd2-402e-86b2-d656296416f3"
|
||||||
}
|
}
|
||||||
@@ -1 +1 @@
|
|||||||
{"session_id":"ef02339a-1eec-4c7a-95ac-c8cfa0b5067d","transcript_path":"/Users/cillin/.claude/projects/-Users-cillin-workspeace-evotraders/ef02339a-1eec-4c7a-95ac-c8cfa0b5067d.jsonl","cwd":"/Users/cillin/workspeace/evotraders","model":{"id":"MiniMax-M2.7-highspeed","display_name":"MiniMax-M2.7-highspeed"},"workspace":{"current_dir":"/Users/cillin/workspeace/evotraders","project_dir":"/Users/cillin/workspeace/evotraders","added_dirs":[]},"version":"2.1.78","output_style":{"name":"default"},"cost":{"total_cost_usd":17.458779250000003,"total_duration_ms":1866224,"total_api_duration_ms":1188013,"total_lines_added":257,"total_lines_removed":290},"context_window":{"total_input_tokens":195204,"total_output_tokens":48917,"context_window_size":200000,"current_usage":{"input_tokens":481,"output_tokens":0,"cache_creation_input_tokens":149,"cache_read_input_tokens":163286},"used_percentage":82,"remaining_percentage":18},"exceeds_200k_tokens":false}
|
{"session_id":"fda34772-7bd2-402e-86b2-d656296416f3","transcript_path":"/Users/cillin/.claude/projects/-Users-cillin-workspeace-evotraders/fda34772-7bd2-402e-86b2-d656296416f3.jsonl","cwd":"/Users/cillin/workspeace/evotraders","model":{"id":"MiniMax-M2.7-highspeed","display_name":"MiniMax-M2.7-highspeed"},"workspace":{"current_dir":"/Users/cillin/workspeace/evotraders","project_dir":"/Users/cillin/workspeace/evotraders","added_dirs":[]},"version":"2.1.78","output_style":{"name":"default"},"cost":{"total_cost_usd":36.63980749999998,"total_duration_ms":69778027,"total_api_duration_ms":2925118,"total_lines_added":3056,"total_lines_removed":4537},"context_window":{"total_input_tokens":910503,"total_output_tokens":145207,"context_window_size":200000,"current_usage":{"input_tokens":507,"output_tokens":247,"cache_creation_input_tokens":4132,"cache_read_input_tokens":96553},"used_percentage":51,"remaining_percentage":49},"exceeds_200k_tokens":false}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"lastSentAt": "2026-03-19T17:02:32.170Z"
|
"lastSentAt": "2026-03-24T08:58:57.965Z"
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,26 @@
|
|||||||
{
|
{
|
||||||
"agents": [
|
"agents": [
|
||||||
{
|
{
|
||||||
"agent_id": "a8305a91e192b2196",
|
"agent_id": "abeaf609b74a2b7ee",
|
||||||
"agent_type": "Explore",
|
"agent_type": "Explore",
|
||||||
"started_at": "2026-03-19T17:00:33.284Z",
|
"started_at": "2026-03-24T08:01:40.015Z",
|
||||||
"parent_mode": "none",
|
"parent_mode": "none",
|
||||||
"status": "completed",
|
"status": "completed",
|
||||||
"completed_at": "2026-03-19T17:02:19.439Z",
|
"completed_at": "2026-03-24T08:02:31.822Z",
|
||||||
"duration_ms": 106155
|
"duration_ms": 51807
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"agent_id": "afb6750eaae72bc72",
|
||||||
|
"agent_type": "Explore",
|
||||||
|
"started_at": "2026-03-24T08:56:21.471Z",
|
||||||
|
"parent_mode": "none",
|
||||||
|
"status": "completed",
|
||||||
|
"completed_at": "2026-03-24T08:57:27.856Z",
|
||||||
|
"duration_ms": 66385
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"total_spawned": 1,
|
"total_spawned": 2,
|
||||||
"total_completed": 1,
|
"total_completed": 2,
|
||||||
"total_failed": 0,
|
"total_failed": 0,
|
||||||
"last_updated": "2026-03-19T17:02:39.175Z"
|
"last_updated": "2026-03-24T08:59:06.380Z"
|
||||||
}
|
}
|
||||||
392
CLAUDE.md
392
CLAUDE.md
@@ -1,5 +1,7 @@
|
|||||||
# CLAUDE.md
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
本文件为 Claude Code (claude.ai/code) 在此代码库中工作时提供指导。
|
本文件为 Claude Code (claude.ai/code) 在此代码库中工作时提供指导。
|
||||||
|
|
||||||
## 项目概述
|
## 项目概述
|
||||||
@@ -23,18 +25,20 @@ evotraders live -t 22:30 # 定时每日交易
|
|||||||
evotraders frontend # 启动可视化界面
|
evotraders frontend # 启动可视化界面
|
||||||
|
|
||||||
# 开发服务器
|
# 开发服务器
|
||||||
./start-dev.sh # 启动全部 4 个微服务
|
./start-dev.sh # 启动全部 4 个微服务 (agent, runtime, trading, news)
|
||||||
|
|
||||||
# 单独启动某个服务
|
# Gateway WebSocket 服务器
|
||||||
python -m uvicorn backend.apps.agent_service:app --host 0.0.0.0 --port 8000 --reload
|
python backend/main.py --mode live --config-name mock --mock
|
||||||
|
|
||||||
|
# 单独启动微服务
|
||||||
python -m uvicorn backend.apps.runtime_service:app --host 0.0.0.0 --port 8003 --reload
|
python -m uvicorn backend.apps.runtime_service:app --host 0.0.0.0 --port 8003 --reload
|
||||||
|
python -m uvicorn backend.apps.agent_service:app --host 0.0.0.0 --port 8000 --reload
|
||||||
python -m uvicorn backend.apps.trading_service:app --host 0.0.0.0 --port 8001 --reload
|
python -m uvicorn backend.apps.trading_service:app --host 0.0.0.0 --port 8001 --reload
|
||||||
python -m uvicorn backend.apps.news_service:app --host 0.0.0.0 --port 8002 --reload
|
python -m uvicorn backend.apps.news_service:app --host 0.0.0.0 --port 8002 --reload
|
||||||
|
|
||||||
# 测试
|
# 测试
|
||||||
pytest backend/tests # 运行全部测试
|
pytest backend/tests # 运行全部测试
|
||||||
pytest backend/tests/test_news_service_app.py -v # 运行单个测试文件
|
pytest backend/tests/test_news_service_app.py -v # 运行单个测试
|
||||||
pytest backend/tests/test_news_service_app.py::test_news_service_routes_are_exposed -v # 运行单个测试
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Frontend (React)
|
### Frontend (React)
|
||||||
@@ -46,142 +50,237 @@ npm run build # 生产构建
|
|||||||
npm run lint # ESLint 检查
|
npm run lint # ESLint 检查
|
||||||
npm run lint:fix # ESLint 自动修复
|
npm run lint:fix # ESLint 自动修复
|
||||||
npm run test # Vitest 单元测试
|
npm run test # Vitest 单元测试
|
||||||
npm run test:watch # 监听模式
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 架构概览
|
## 架构概览
|
||||||
|
|
||||||
### 微服务架构 (`backend/apps/`)
|
### 系统分层
|
||||||
|
|
||||||
项目采用 split-first 微服务架构,4 个独立的 FastAPI 服务:
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
| 服务 | 入口 | 端口 | 职责 |
|
│ Frontend (React) │
|
||||||
|------|------|------|------|
|
│ WebSocket ws://localhost:8765 连接 Gateway │
|
||||||
| agent_service | `backend.apps.agent_service:app` | 8000 | Agent 生命周期、工作区管理 |
|
└─────────────────────────────────────────────────────────────┘
|
||||||
| runtime_service | `backend.apps.runtime_service:app` | 8003 | 运行时配置、任务启动 |
|
│
|
||||||
| trading_service | `backend.apps.trading_service:app` | 8001 | 市场数据、交易操作 |
|
▼
|
||||||
| news_service | `backend.apps.news_service:app` | 8002 | 新闻、新闻富化、解释功能 |
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ Gateway (backend/services/gateway.py) │
|
||||||
服务间通过环境变量通信(详见 `start-dev.sh`):
|
│ WebSocket 服务器,编排 Pipeline,4 阶段启动 │
|
||||||
```bash
|
└─────────────────────────────────────────────────────────────┘
|
||||||
export TRADING_SERVICE_URL=http://localhost:8001
|
│ │ │ │
|
||||||
export NEWS_SERVICE_URL=http://localhost:8002
|
▼ ▼ ▼ ▼
|
||||||
export RUNTIME_SERVICE_URL=http://localhost:8003
|
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
|
||||||
|
│ Market │ │ Storage │ │ Pipeline │ │ Scheduler │
|
||||||
|
│ Service │ │ Service │ │ │ │ │
|
||||||
|
└────────────┘ └────────────┘ └────────────┘ └────────────┘
|
||||||
|
│
|
||||||
|
┌──────────────────────┼──────────────────────┐
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||||
|
│ Analysts │ │ PM │ │ Risk │
|
||||||
|
│ (4 个) │ │ │ │ Manager │
|
||||||
|
└──────────┘ └──────────┘ └──────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
### Gateway 网关 (`backend/services/gateway.py`)
|
### 微服务架构 (`backend/apps/`)
|
||||||
|
|
||||||
Gateway 是统一的请求路由器,根据路径前缀将请求转发到对应的微服务:
|
| 服务 | 端口 | 职责 |
|
||||||
- `/control/*` → agent_service
|
|------|------|------|
|
||||||
- `/runtime/*` → runtime_service
|
| runtime_service | 8003 | 运行时配置、任务启动、Pipeline Runner |
|
||||||
- `/trading/*` → trading_service
|
| agent_service | 8000 | Agent 生命周期、工作区管理 |
|
||||||
- `/news/*` → news_service
|
| trading_service | 8001 | 市场数据、交易操作 |
|
||||||
|
| news_service | 8002 | 新闻、新闻富化、解释功能 |
|
||||||
|
|
||||||
新增接口时应注册到对应的 service app,而非直接添加到 gateway。
|
### Gateway 4 阶段启动 (`backend/services/gateway.py`)
|
||||||
|
|
||||||
### 共享客户端 (`shared/client/`)
|
1. **WebSocket Server** - 前端立即可连接
|
||||||
|
2. **Market Service** - 价格数据开始推送
|
||||||
|
3. **Market Status Monitor** - 市场状态监控
|
||||||
|
4. **Scheduler** - 交易周期开始
|
||||||
|
|
||||||
统一的服务客户端库,所有前端和后端服务间通信都使用此处定义的客户端:
|
### 运行时管理层 (`backend/runtime/`)
|
||||||
|
|
||||||
| 客户端 | 用途 |
|
| 文件 | 职责 |
|
||||||
|--------|------|
|
|------|------|
|
||||||
| `ControlPlaneClient` | Agent 服务通信 |
|
| `manager.py` | TradingRuntimeManager - 全局运行时管理器,agent 注册、会话、事件快照 |
|
||||||
| `RuntimeServiceClient` | 运行时服务通信 |
|
| `agent_runtime.py` | AgentRuntimeState - 单 agent 状态(status、last_session) |
|
||||||
| `TradingServiceClient` | 交易服务通信 |
|
| `context.py` | TradingRunContext - 运行上下文 |
|
||||||
| `NewsServiceClient` | 新闻服务通信 |
|
| `session.py` | TradingSessionKey - 交易日会话键 |
|
||||||
|
| `registry.py` | RuntimeRegistry - agent 状态注册表 |
|
||||||
|
|
||||||
### 领域层 (`backend/domains/`)
|
快照持久化到 `runs/<run_id>/state/runtime_state.json`。
|
||||||
|
|
||||||
业务逻辑按领域分离:
|
### Pipeline 执行 (`backend/core/`)
|
||||||
|
|
||||||
- `news.py` - 新闻领域操作
|
| 文件 | 职责 |
|
||||||
- `trading.py` - 交易领域操作
|
|------|------|
|
||||||
|
| `pipeline.py` | TradingPipeline - 核心编排器(分析→沟通→决策→执行→评估) |
|
||||||
|
| `pipeline_runner.py` | REST API 触发的独立执行,5 阶段启动 |
|
||||||
|
| `scheduler.py` | BacktestScheduler、Scheduler - 回测/实盘调度 |
|
||||||
|
| `state_sync.py` | StateSync - 状态同步和广播 |
|
||||||
|
|
||||||
## 后端结构
|
## 后端结构
|
||||||
|
|
||||||
```
|
```
|
||||||
backend/
|
backend/
|
||||||
├── agents/ # 多智能体实现
|
├── agents/ # 多智能体实现
|
||||||
│ ├── base/ # 核心类、Hooks、评估
|
│ ├── analyst.py # AnalystAgent 基类
|
||||||
│ │ ├── evo_agent.py # 基于 AgentScope 的核心实现
|
│ ├── portfolio_manager.py # PMAgent 投资经理
|
||||||
│ │ ├── hooks.py # 生命周期 Hooks
|
│ ├── risk_manager.py # RiskAgent 风控经理
|
||||||
│ │ │ ├── BootstrapHook # 启动初始化
|
|
||||||
│ │ │ ├── MemoryCompactionHook # 内存压缩(基于 CoPaw)
|
|
||||||
│ │ │ ├── HeartbeatHook # 心跳检测
|
|
||||||
│ │ │ └── WorkspaceWatchHook # 工作区监控
|
|
||||||
│ │ ├── evaluation_hook.py # 执行后评估
|
|
||||||
│ │ ├── skill_adaptation_hook.py # 动态技能适配
|
|
||||||
│ │ └── tool_guard.py # 工具调用守卫
|
|
||||||
│ ├── prompts/ # Agent 提示词和角色定义
|
|
||||||
│ │ ├── analyst/personas.yaml # 分析师角色配置
|
|
||||||
│ │ └── portfolio_manager/
|
|
||||||
│ ├── team/ # 团队协作逻辑
|
|
||||||
│ │ ├── registry.py # Agent 注册表
|
|
||||||
│ │ ├── coordinator.py # 协作协调器
|
|
||||||
│ │ ├── messenger.py # 消息传递
|
|
||||||
│ │ └── task_delegator.py # 任务分发
|
|
||||||
│ ├── factory.py # Agent 实例工厂
|
│ ├── factory.py # Agent 实例工厂
|
||||||
│ ├── skills_manager.py # 技能加载管理(6 种作用域)
|
│ ├── toolkit_factory.py # 工具集工厂
|
||||||
│ └── toolkit_factory.py # 工具集工厂
|
│ ├── skills_manager.py # 技能加载管理
|
||||||
├── apps/ # 微服务入口(split-first)
|
│ ├── workspace_manager.py # 工作区管理
|
||||||
│ ├── agent_service.py
|
│ ├── skill_loader.py # 技能加载器
|
||||||
│ ├── runtime_service.py
|
│ ├── agent_workspace.py # Agent 工作区
|
||||||
│ ├── trading_service.py
|
│ ├── prompt_loader.py # Prompt 加载器
|
||||||
│ └── news_service.py
|
│ ├── prompt_factory.py # Prompt 工厂
|
||||||
|
│ ├── skill_metadata.py # 技能元数据
|
||||||
|
│ ├── registry.py # Agent 注册表
|
||||||
|
│ ├── team_pipeline_config.py # 团队 Pipeline 配置
|
||||||
|
│ ├── compat.py # 兼容性层
|
||||||
|
│ ├── templates.py # 模板
|
||||||
|
│ ├── workspace.py # 工作区
|
||||||
|
│ ├── base/ # 核心类、Hooks
|
||||||
|
│ │ ├── evo_agent.py # 基于 AgentScope 的核心实现
|
||||||
|
│ │ └── hooks.py # 生命周期 Hooks
|
||||||
|
│ └── prompts/ # Agent 提示词
|
||||||
|
│ └── analyst/personas.yaml
|
||||||
|
│
|
||||||
|
├── apps/ # 微服务入口
|
||||||
|
│ ├── runtime_service.py # 运行时服务(端口 8003)
|
||||||
|
│ ├── agent_service.py # Agent 服务(端口 8000)
|
||||||
|
│ ├── trading_service.py # 交易服务(端口 8001)
|
||||||
|
│ ├── news_service.py # 新闻服务(端口 8002)
|
||||||
|
│ └── cors.py
|
||||||
|
│
|
||||||
|
├── runtime/ # 运行时管理层
|
||||||
|
│ ├── manager.py # TradingRuntimeManager
|
||||||
|
│ ├── agent_runtime.py # AgentRuntimeState
|
||||||
|
│ ├── context.py # TradingRunContext
|
||||||
|
│ ├── session.py # TradingSessionKey
|
||||||
|
│ └── registry.py # RuntimeRegistry
|
||||||
|
│
|
||||||
|
├── process/ # 进程监管层
|
||||||
|
│ ├── supervisor.py # ProcessSupervisor
|
||||||
|
│ ├── registry.py # RunRegistry
|
||||||
|
│ └── models.py # ProcessRun、ProcessRunState
|
||||||
|
│
|
||||||
|
├── core/ # Pipeline 执行
|
||||||
|
│ ├── pipeline.py # TradingPipeline(核心编排器)
|
||||||
|
│ ├── pipeline_runner.py # 独立 Pipeline 执行
|
||||||
|
│ ├── scheduler.py # 调度器
|
||||||
|
│ └── state_sync.py # 状态同步
|
||||||
|
│
|
||||||
|
├── services/ # Gateway 和服务
|
||||||
|
│ ├── gateway.py # WebSocket 网关
|
||||||
|
│ ├── gateway_*.py # Gateway 子模块
|
||||||
|
│ ├── market.py # 市场数据服务
|
||||||
|
│ ├── storage.py # 存储服务
|
||||||
|
│ ├── runtime_db.py # 运行时数据库
|
||||||
|
│ └── research_db.py # 研究数据库
|
||||||
|
│
|
||||||
|
├── data/ # 市场数据处理
|
||||||
|
│ ├── provider_router.py # 数据源路由
|
||||||
|
│ ├── provider_utils.py # 数据源工具
|
||||||
|
│ ├── market_store.py # 市场数据存储
|
||||||
|
│ ├── market_ingest.py # 数据采集
|
||||||
|
│ ├── cache.py # 缓存
|
||||||
|
│ ├── schema.py # 数据 schema
|
||||||
|
│ ├── historical_price_manager.py # 历史价格管理
|
||||||
|
│ ├── polling_price_manager.py # 轮询价格管理
|
||||||
|
│ ├── mock_price_manager.py # Mock 价格管理
|
||||||
|
│ ├── news_alignment.py # 新闻对齐
|
||||||
|
│ ├── polygon_client.py # Polygon.io 客户端
|
||||||
|
│ └── ret_data_updater.py # 离线数据更新
|
||||||
|
│
|
||||||
|
├── config/ # 配置
|
||||||
|
│ ├── constants.py # Agent 配置、显示名称
|
||||||
|
│ ├── bootstrap_config.py # 启动配置解析
|
||||||
|
│ ├── env_config.py # 环境变量配置
|
||||||
|
│ ├── data_config.py # 数据源配置
|
||||||
|
│ └── agent_profiles.yaml # Agent Profile 配置
|
||||||
|
│
|
||||||
├── domains/ # 领域业务逻辑
|
├── domains/ # 领域业务逻辑
|
||||||
│ ├── news.py
|
│ ├── news.py
|
||||||
│ └── trading.py
|
│ └── trading.py
|
||||||
├── services/ # Gateway 和辅助服务
|
│
|
||||||
│ ├── gateway.py # 统一路由网关
|
|
||||||
│ ├── gateway_*.py # Gateway 子模块
|
|
||||||
│ └── market.py # 市场数据服务
|
|
||||||
├── api/ # FastAPI 端点
|
|
||||||
├── config/ # 常量和配置
|
|
||||||
│ └── constants.py # Agent 配置、显示名称等
|
|
||||||
├── core/ # Pipeline 执行逻辑
|
|
||||||
├── data/ # 市场数据处理
|
|
||||||
│ ├── provider_router.py # 数据源路由
|
|
||||||
│ └── schema.py # 数据 schema
|
|
||||||
├── enrich/ # LLM 响应富化
|
|
||||||
├── explain/ # 交易决策解释
|
|
||||||
├── llm/ # LLM 集成
|
├── llm/ # LLM 集成
|
||||||
│ └── models.py # RetryChatModel、TokenRecordingModelWrapper
|
│ └── models.py # RetryChatModel、TokenRecordingModelWrapper
|
||||||
├── skills/ # 技能定义(内置 + 自定义)
|
│
|
||||||
|
├── skills/ # 技能定义
|
||||||
├── tools/ # 交易和分析工具
|
├── tools/ # 交易和分析工具
|
||||||
└── utils/ # 工具函数
|
├── enrich/ # LLM 响应富化
|
||||||
|
├── explain/ # 交易决策解释
|
||||||
|
├── utils/ # 工具函数
|
||||||
|
│ ├── settlement.py # 结算协调器
|
||||||
|
│ ├── trade_executor.py # 交易执行器
|
||||||
|
│ ├── terminal_dashboard.py # 终端仪表板
|
||||||
|
│ ├── analyst_tracker.py # 分析师追踪
|
||||||
|
│ ├── baselines.py # 基准线
|
||||||
|
│ ├── msg_adapter.py # 消息适配器
|
||||||
|
│ └── progress.py # 进度追踪
|
||||||
|
│
|
||||||
|
├── api/ # FastAPI 端点
|
||||||
|
│ └── runtime.py
|
||||||
|
│
|
||||||
|
└── main.py # 主入口点
|
||||||
```
|
```
|
||||||
|
|
||||||
## 前端结构
|
## 前端结构
|
||||||
|
|
||||||
```
|
```
|
||||||
frontend/src/
|
frontend/src/
|
||||||
├── App.jsx # React 主应用
|
├── App.jsx # 主应用(LiveTradingApp)
|
||||||
├── components/ # React 组件
|
├── AppShell.jsx # App 外壳(布局、侧边栏)
|
||||||
|
├── components/
|
||||||
│ ├── RuntimeView.jsx # 交易运行时 UI
|
│ ├── RuntimeView.jsx # 交易运行时 UI
|
||||||
│ ├── TraderView.jsx # 交易员界面
|
│ ├── TraderView.jsx # 交易员界面
|
||||||
│ ├── RoomView.jsx # 聊天室视图
|
│ ├── RoomView.jsx # 聊天室视图
|
||||||
│ ├── StockExplainView.jsx # 股票解释视图
|
│ ├── StockExplainView.jsx # 股票解释视图
|
||||||
│ ├── RuntimeSettingsPanel.jsx # 运行时设置面板
|
│ ├── RuntimeSettingsPanel.jsx # 运行时设置面板
|
||||||
|
│ ├── RuntimeLogsModal.jsx # 运行时日志弹窗
|
||||||
│ ├── WatchlistPanel.jsx # 关注列表
|
│ ├── WatchlistPanel.jsx # 关注列表
|
||||||
│ ├── PerformanceView.jsx # 绩效视图
|
│ ├── PerformanceView.jsx # 绩效视图
|
||||||
│ ├── StatisticsView.jsx # 统计视图
|
│ ├── StatisticsView.jsx # 统计视图
|
||||||
│ ├── NetValueChart.jsx # 净值曲线图
|
│ ├── NetValueChart.jsx # 净值曲线图
|
||||||
│ ├── AgentCard.jsx # Agent 卡片
|
│ ├── AgentCard.jsx # Agent 卡片
|
||||||
│ ├── AgentFeed.jsx # Agent 动态
|
│ ├── AgentFeed.jsx # Agent 动态
|
||||||
│ └── explain/ # 解释相关组件
|
│ ├── Header.jsx # 头部
|
||||||
|
│ ├── MarkdownModal.jsx # Markdown 弹窗
|
||||||
|
│ ├── StockLogo.jsx # 股票 Logo
|
||||||
|
│ └── explain/ # 解释组件
|
||||||
│ ├── ExplainNewsSection.jsx
|
│ ├── ExplainNewsSection.jsx
|
||||||
│ ├── ExplainRangeSection.jsx
|
│ ├── ExplainRangeSection.jsx
|
||||||
│ ├── ExplainSimilarDaysSection.jsx
|
│ ├── ExplainSimilarDaysSection.jsx
|
||||||
│ ├── ExplainStorySection.jsx
|
│ ├── ExplainStorySection.jsx
|
||||||
│ └── useExplainModel.js
|
│ └── useExplainModel.js
|
||||||
├── services/ # API 服务
|
├── hooks/ # React Hooks
|
||||||
│ ├── runtimeApi.js # 运行时 API 调用
|
│ ├── useWebSocketConnection.js # WebSocket 连接管理
|
||||||
│ ├── websocket.js # WebSocket 实时通信
|
│ ├── useRuntimeControls.js # 运行时配置管理
|
||||||
│ ├── newsApi.js # 新闻服务客户端
|
│ ├── useAgentDataRequests.js # Agent 数据请求
|
||||||
│ └── tradingApi.js # 交易服务客户端
|
│ ├── useStockDataRequests.js # 股票数据请求
|
||||||
├── config/
|
│ ├── useStockExplainData.js # 股票解释数据
|
||||||
│ └── constants.js # Agent 定义、配置
|
│ ├── useAgentWorkspacePanel.js # Agent 工作区面板
|
||||||
└── hooks/ # React Hooks
|
│ ├── useWebsocketSessionSync.js # WebSocket 会话同步
|
||||||
|
│ └── useFeedProcessor.js # Feed 事件处理
|
||||||
|
├── store/ # Zustand 状态管理
|
||||||
|
│ ├── runtimeStore.js # 连接状态、运行时配置
|
||||||
|
│ ├── marketStore.js # 市场数据、股票价格
|
||||||
|
│ ├── portfolioStore.js # 组合、持仓、交易
|
||||||
|
│ ├── agentStore.js # Agent 技能、工作区
|
||||||
|
│ └── uiStore.js # UI 状态、视图切换
|
||||||
|
├── services/
|
||||||
|
│ ├── websocket.js # WebSocket 客户端
|
||||||
|
│ ├── runtimeApi.js # 运行时 API
|
||||||
|
│ ├── runtimeControls.js # 运行时控制
|
||||||
|
│ ├── newsApi.js # 新闻 API
|
||||||
|
│ └── tradingApi.js # 交易 API
|
||||||
|
├── utils/
|
||||||
|
│ ├── formatters.js # 格式化工具
|
||||||
|
│ └── modelIcons.js # 模型图标
|
||||||
|
└── config/
|
||||||
|
└── constants.js # Agent 定义、配置
|
||||||
```
|
```
|
||||||
|
|
||||||
## Agent 系统
|
## Agent 系统
|
||||||
@@ -193,110 +292,87 @@ frontend/src/
|
|||||||
| `fundamentals_analyst` | 基本面分析师 | 财务健康、盈利能力、成长质量 |
|
| `fundamentals_analyst` | 基本面分析师 | 财务健康、盈利能力、成长质量 |
|
||||||
| `technical_analyst` | 技术分析师 | 价格趋势、技术指标、动量分析 |
|
| `technical_analyst` | 技术分析师 | 价格趋势、技术指标、动量分析 |
|
||||||
| `sentiment_analyst` | 情绪分析师 | 市场情绪、新闻情绪、内幕交易 |
|
| `sentiment_analyst` | 情绪分析师 | 市场情绪、新闻情绪、内幕交易 |
|
||||||
| `valuation_analyst` | 估值分析师 | DCF、EV/EBITDA、 intrinsic value |
|
| `valuation_analyst` | 估值分析师 | DCF、EV/EBITDA、intrinsic value |
|
||||||
| `portfolio_manager` | 投资经理 | 决策执行、交易协调 |
|
| `portfolio_manager` | 投资经理 | 决策执行、交易协调 |
|
||||||
| `risk_manager` | 风控经理 | 实时价格/波动率监控、仓位限制、多层风险预警 |
|
| `risk_manager` | 风控经理 | 实时价格/波动率监控、仓位限制 |
|
||||||
|
|
||||||
### Hook 系统 (`base/hooks.py`)
|
|
||||||
|
|
||||||
- **MemoryCompactionHook**: 基于 CoPaw 的内存压缩
|
|
||||||
- `memory_compact_ratio`: 压缩目标比例(默认 0.75)
|
|
||||||
- `memory_reserve_ratio`: 保留比例(默认 0.1)
|
|
||||||
- `enable_tool_result_compact`: 工具结果压缩
|
|
||||||
- `tool_result_compact_keep_n`: 保留最近 N 条工具结果
|
|
||||||
|
|
||||||
### 添加自定义分析师
|
### 添加自定义分析师
|
||||||
|
|
||||||
1. 在 `backend/agents/prompts/analyst/personas.yaml` 注册
|
1. `backend/agents/prompts/analyst/personas.yaml` 注册
|
||||||
2. 在 `backend/config/constants.py` 的 `ANALYST_TYPES` 字典中添加
|
2. `backend/config/constants.py` 的 `ANALYST_TYPES` 字典添加
|
||||||
3. 可选:在 `frontend/src/config/constants.js` 中更新前端配置
|
3. `frontend/src/config/constants.js` 可选更新
|
||||||
|
|
||||||
### LLM 模型封装 (`backend/llm/models.py`)
|
### LLM 模型封装 (`backend/llm/models.py`)
|
||||||
|
|
||||||
基于 CoPaw 的模型封装设计:
|
- **RetryChatModel**: 自动重试瞬态 LLM 错误,指数退避
|
||||||
|
- **TokenRecordingModelWrapper**: 追踪 token 消耗和成本
|
||||||
- **RetryChatModel**: 自动重试瞬态 LLM 错误(rate limit、timeout、502/503 等),指数退避
|
|
||||||
- `max_retries`: 最大重试次数(默认 3)
|
|
||||||
- `initial_delay`: 初始延迟秒数(默认 1.0)
|
|
||||||
- `backoff_multiplier`: 退避倍数(默认 2.0)
|
|
||||||
|
|
||||||
- **TokenRecordingModelWrapper**: 追踪每个 provider 的 token 消耗和成本
|
|
||||||
|
|
||||||
```python
|
|
||||||
from backend.llm.models import create_model, RetryChatModel
|
|
||||||
|
|
||||||
model = RetryChatModel(create_model("gpt-4o", "OPENAI"), max_retries=3)
|
|
||||||
```
|
|
||||||
|
|
||||||
## 技能系统 (`backend/skills/`)
|
## 技能系统 (`backend/skills/`)
|
||||||
|
|
||||||
技能定义在 `SKILL.md` 文件中,包含:
|
技能定义在 `SKILL.md`,包含 `instructions`、`triggers`、`parameters`、`available_tools`。
|
||||||
- `instructions` - 技能说明
|
|
||||||
- `triggers` - 触发条件
|
|
||||||
- `parameters` - 输入/输出 schema
|
|
||||||
- `available_tools` - 技能可使用的工具
|
|
||||||
|
|
||||||
技能由 `skills_manager.py` 加载,通过 `skill_adaptation_hook.py` 绑定到 Agent。
|
|
||||||
|
|
||||||
技能管理器支持 6 种作用域:builtin、customized、installed、active、disabled、local。
|
技能管理器支持 6 种作用域:builtin、customized、installed、active、disabled、local。
|
||||||
|
|
||||||
## Pipeline 执行 (`backend/core/`)
|
## 运行时数据布局
|
||||||
|
|
||||||
每日交易流程:
|
- `data/market_research.db` - 持久研究数据
|
||||||
|
- `runs/<run_id>/` - 每次任务运行的状态
|
||||||
1. **分析阶段** - 各 Agent 基于工具和历史经验独立分析
|
- `runs/<run_id>/team_dashboard/*.json` - 仪表板导出层(非权威源)
|
||||||
2. **沟通阶段** - 通过私聊、通知、会议等方式交换观点(1v1/1vN/NvN)
|
- `runs/<run_id>/state/runtime_state.json` - 运行时快照
|
||||||
3. **决策阶段** - 投资经理综合判断,给出最终交易
|
- 运行时 API 优先使用 `server_state.json` 和 `runtime.db`
|
||||||
4. **评估阶段** - 绩效跟踪
|
|
||||||
5. **复盘阶段** - Agent 根据当日实际收益反思总结,通过 ReMe 记忆框架更新经验
|
|
||||||
|
|
||||||
## 前端状态管理
|
|
||||||
|
|
||||||
项目正在向 Zustand 状态管理过渡,已创建的 store:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
frontend/src/store/
|
RUNS_RETENTION_COUNT=20 # 时间戳格式文件夹自动清理
|
||||||
├── index.js # 导出所有 store
|
|
||||||
├── runtimeStore.js # 连接状态、运行时配置
|
|
||||||
├── marketStore.js # 市场数据、股票价格
|
|
||||||
├── portfolioStore.js # 组合、持仓、交易
|
|
||||||
├── agentStore.js # Agent 技能、工作区
|
|
||||||
└── uiStore.js # UI 状态、视图切换
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**迁移状态**:
|
|
||||||
- Stores 已创建但尚未在 App.jsx 中使用
|
|
||||||
- 计划:逐步迁移 60+ 个 useState 到对应 store
|
|
||||||
|
|
||||||
## 环境配置
|
## 环境配置
|
||||||
|
|
||||||
`.env` 必需配置:
|
### Backend (`env.template`)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 金融数据源
|
# 金融数据源(支持多源fallback)
|
||||||
FIN_DATA_SOURCE=finnhub|financial_datasets
|
FIN_DATA_SOURCE=finnhub|financial_datasets|yfinance|local_csv
|
||||||
|
ENABLED_DATA_SOURCES=financial_datasets,finnhub,yfinance,local_csv
|
||||||
FINANCIAL_DATASETS_API_KEY= # 回测必需
|
FINANCIAL_DATASETS_API_KEY= # 回测必需
|
||||||
FINNHUB_API_KEY= # 实盘必需
|
FINNHUB_API_KEY= # 实盘必需
|
||||||
|
POLYGON_API_KEY= # Polygon市场库采集可选
|
||||||
|
|
||||||
# Agent LLM
|
# LLM 配置
|
||||||
OPENAI_API_KEY=
|
OPENAI_API_KEY=
|
||||||
OPENAI_BASE_URL=
|
OPENAI_BASE_URL=
|
||||||
MODEL_NAME=qwen3-max-preview
|
MODEL_NAME=qwen3-max-preview
|
||||||
|
|
||||||
# 可为不同 Agent 指定不同模型
|
# Agent 特定模型
|
||||||
AGENT_SENTIMENT_ANALYST_MODEL_NAME=qwen3-max-preview
|
AGENT_SENTIMENT_ANALYST_MODEL_NAME=deepseek-v3.2-exp
|
||||||
AGENT_FUNDAMENTALS_ANALYST_MODEL_NAME=deepseek-chat
|
AGENT_TECHNICAL_ANALYST_MODEL_NAME=glm-4.6
|
||||||
|
AGENT_FUNDAMENTALS_ANALYST_MODEL_NAME=qwen3-max-preview
|
||||||
|
AGENT_VALUATION_ANALYST_MODEL_NAME=Moonshot-Kimi-K2-Instruct
|
||||||
|
AGENT_RISK_MANAGER_MODEL_NAME=qwen3-max-preview
|
||||||
|
AGENT_PORTFOLIO_MANAGER_MODEL_NAME=qwen3-max-preview
|
||||||
|
|
||||||
# ReMe 记忆系统
|
# ReMe 记忆系统
|
||||||
MEMORY_API_KEY=
|
MEMORY_API_KEY=
|
||||||
|
MEMORY_MODEL_NAME=qwen3-max
|
||||||
|
MEMORY_EMBEDDING_MODEL=text-embedding-v4
|
||||||
|
|
||||||
|
# 交易参数
|
||||||
|
MAX_COMM_CYCLES=2
|
||||||
|
MARGIN_REQUIREMENT=0.5
|
||||||
|
DATA_START_DATE=2022-01-01
|
||||||
|
AUTO_UPDATE_DATA=true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Frontend (`frontend/env.template`)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
VITE_WS_URL=ws://localhost:8765
|
||||||
```
|
```
|
||||||
|
|
||||||
## 关键依赖
|
## 关键依赖
|
||||||
|
|
||||||
- **AgentScope** - 多智能体框架
|
- **AgentScope** - 多智能体框架
|
||||||
- **ReMe** - 持续学习记忆系统
|
- **ReMe** - 持续学习记忆系统
|
||||||
- **FastAPI** + **uvicorn** - 后端 API 服务器
|
- **FastAPI** + **uvicorn** - 后端 API
|
||||||
- **websockets** - 实时通信
|
- **websockets** - 实时通信
|
||||||
- **React 19** + **Vite** + **TailwindCSS** - 前端
|
- **React 19** + **Vite** + **TailwindCSS** - 前端
|
||||||
- **React Context** - 前端状态管理(App.jsx 中使用 useState + useCallback)
|
- **Zustand** - 状态管理
|
||||||
- **Three.js** / **React-Three-Fiber** - 3D 可视化
|
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ class SkillsManager:
|
|||||||
)
|
)
|
||||||
self.runs_root = self.project_root / "runs"
|
self.runs_root = self.project_root / "runs"
|
||||||
self._lock = Lock()
|
self._lock = Lock()
|
||||||
|
# Instance-level pending skill changes (thread-safe via self._lock)
|
||||||
|
self._pending_skill_changes: Dict[str, Set[Path]] = {}
|
||||||
|
|
||||||
def get_active_root(self, config_name: str) -> Path:
|
def get_active_root(self, config_name: str) -> Path:
|
||||||
return self.runs_root / config_name / "skills" / "active"
|
return self.runs_root / config_name / "skills" / "active"
|
||||||
@@ -739,7 +741,7 @@ class SkillsManager:
|
|||||||
if local_root.exists():
|
if local_root.exists():
|
||||||
watched_paths.append(local_root)
|
watched_paths.append(local_root)
|
||||||
|
|
||||||
handler = _SkillsChangeHandler(watched_paths, callback, self._lock)
|
handler = _SkillsChangeHandler(watched_paths, self._pending_skill_changes, callback, self._lock)
|
||||||
observer = Observer()
|
observer = Observer()
|
||||||
for path in watched_paths:
|
for path in watched_paths:
|
||||||
observer.schedule(handler, str(path), recursive=True)
|
observer.schedule(handler, str(path), recursive=True)
|
||||||
@@ -773,6 +775,7 @@ class SkillsManager:
|
|||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# Internal change-tracking state (populated by _SkillsChangeHandler)
|
# Internal change-tracking state (populated by _SkillsChangeHandler)
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
|
# Legacy class-level reference kept for migration compatibility
|
||||||
_pending_skill_changes: Dict[str, Set[Path]] = {}
|
_pending_skill_changes: Dict[str, Set[Path]] = {}
|
||||||
|
|
||||||
def _resolve_disabled_skill_names(
|
def _resolve_disabled_skill_names(
|
||||||
@@ -824,11 +827,13 @@ class _SkillsChangeHandler(FileSystemEventHandler):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
watched_paths: List[Path],
|
watched_paths: List[Path],
|
||||||
|
pending_changes: Dict[str, Set[Path]],
|
||||||
callback: Optional[Any] = None,
|
callback: Optional[Any] = None,
|
||||||
lock: Optional[Lock] = None,
|
lock: Optional[Lock] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._watched_paths = watched_paths
|
self._watched_paths = watched_paths
|
||||||
|
self._pending_changes = pending_changes
|
||||||
self._callback = callback
|
self._callback = callback
|
||||||
self._lock = lock
|
self._lock = lock
|
||||||
|
|
||||||
@@ -841,13 +846,9 @@ class _SkillsChangeHandler(FileSystemEventHandler):
|
|||||||
run_id = self._run_id_from_path(src_path)
|
run_id = self._run_id_from_path(src_path)
|
||||||
if self._lock:
|
if self._lock:
|
||||||
with self._lock:
|
with self._lock:
|
||||||
SkillsManager._pending_skill_changes.setdefault(
|
self._pending_changes.setdefault(run_id, set()).add(src_path)
|
||||||
run_id, set()
|
|
||||||
).add(src_path)
|
|
||||||
else:
|
else:
|
||||||
SkillsManager._pending_skill_changes.setdefault(
|
self._pending_changes.setdefault(run_id, set()).add(src_path)
|
||||||
run_id, set()
|
|
||||||
).add(src_path)
|
|
||||||
if self._callback:
|
if self._callback:
|
||||||
self._callback([src_path])
|
self._callback([src_path])
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from .runtime_service import app as runtime_app
|
|||||||
from .runtime_service import create_app as create_runtime_app
|
from .runtime_service import create_app as create_runtime_app
|
||||||
from .trading_service import app as trading_app
|
from .trading_service import app as trading_app
|
||||||
from .trading_service import create_app as create_trading_app
|
from .trading_service import create_app as create_trading_app
|
||||||
|
from .cors import add_cors_middleware, get_cors_origins
|
||||||
|
|
||||||
app = agent_app
|
app = agent_app
|
||||||
create_app = create_agent_app
|
create_app = create_agent_app
|
||||||
@@ -24,4 +25,6 @@ __all__ = [
|
|||||||
"create_runtime_app",
|
"create_runtime_app",
|
||||||
"trading_app",
|
"trading_app",
|
||||||
"create_trading_app",
|
"create_trading_app",
|
||||||
|
"add_cors_middleware",
|
||||||
|
"get_cors_origins",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ from pathlib import Path
|
|||||||
from typing import AsyncGenerator
|
from typing import AsyncGenerator
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
|
||||||
|
from backend.apps.cors import add_cors_middleware
|
||||||
|
|
||||||
from backend.api import agents_router, guard_router, workspaces_router
|
from backend.api import agents_router, guard_router, workspaces_router
|
||||||
from backend.agents import AgentFactory, WorkspaceManager, get_registry
|
from backend.agents import AgentFactory, WorkspaceManager, get_registry
|
||||||
@@ -47,13 +48,7 @@ def create_app(project_root: Path | None = None) -> FastAPI:
|
|||||||
lifespan=lifespan,
|
lifespan=lifespan,
|
||||||
)
|
)
|
||||||
|
|
||||||
app.add_middleware(
|
add_cors_middleware(app)
|
||||||
CORSMiddleware,
|
|
||||||
allow_origins=["*"],
|
|
||||||
allow_credentials=True,
|
|
||||||
allow_methods=["*"],
|
|
||||||
allow_headers=["*"],
|
|
||||||
)
|
|
||||||
|
|
||||||
@app.get("/health")
|
@app.get("/health")
|
||||||
async def health_check() -> dict[str, object]:
|
async def health_check() -> dict[str, object]:
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
|
||||||
|
|
||||||
from backend.api import runtime_router
|
from backend.api import runtime_router
|
||||||
from backend.api.runtime import get_runtime_state
|
from backend.api.runtime import get_runtime_state
|
||||||
|
from backend.apps.cors import add_cors_middleware
|
||||||
|
|
||||||
|
|
||||||
def create_app() -> FastAPI:
|
def create_app() -> FastAPI:
|
||||||
@@ -18,13 +18,7 @@ def create_app() -> FastAPI:
|
|||||||
version="0.1.0",
|
version="0.1.0",
|
||||||
)
|
)
|
||||||
|
|
||||||
app.add_middleware(
|
add_cors_middleware(app)
|
||||||
CORSMiddleware,
|
|
||||||
allow_origins=["*"],
|
|
||||||
allow_credentials=True,
|
|
||||||
allow_methods=["*"],
|
|
||||||
allow_headers=["*"],
|
|
||||||
)
|
|
||||||
|
|
||||||
@app.get("/health")
|
@app.get("/health")
|
||||||
async def health_check() -> dict[str, object]:
|
async def health_check() -> dict[str, object]:
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from __future__ import annotations
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from fastapi import FastAPI, Query
|
from fastapi import FastAPI, Query
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from backend.apps.cors import add_cors_middleware
|
||||||
|
|
||||||
from backend.domains import trading as trading_domain
|
from backend.domains import trading as trading_domain
|
||||||
from shared.schema import (
|
from shared.schema import (
|
||||||
@@ -26,13 +26,7 @@ def create_app() -> FastAPI:
|
|||||||
version="0.1.0",
|
version="0.1.0",
|
||||||
)
|
)
|
||||||
|
|
||||||
app.add_middleware(
|
add_cors_middleware(app)
|
||||||
CORSMiddleware,
|
|
||||||
allow_origins=["*"],
|
|
||||||
allow_credentials=True,
|
|
||||||
allow_methods=["*"],
|
|
||||||
allow_headers=["*"],
|
|
||||||
)
|
|
||||||
|
|
||||||
@app.get("/health")
|
@app.get("/health")
|
||||||
async def health_check() -> dict[str, str]:
|
async def health_check() -> dict[str, str]:
|
||||||
|
|||||||
@@ -266,10 +266,6 @@ async def run_pipeline(
|
|||||||
|
|
||||||
set_global_runtime_manager(runtime_manager)
|
set_global_runtime_manager(runtime_manager)
|
||||||
|
|
||||||
# Register runtime manager with API
|
|
||||||
from backend.api.runtime import register_runtime_manager
|
|
||||||
register_runtime_manager(runtime_manager)
|
|
||||||
|
|
||||||
# ======================================================================
|
# ======================================================================
|
||||||
# PHASE 1 & 2: Create infrastructure services (Market, Storage)
|
# PHASE 1 & 2: Create infrastructure services (Market, Storage)
|
||||||
# These will be started by Gateway in the correct order
|
# These will be started by Gateway in the correct order
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import os
|
|||||||
import sqlite3
|
import sqlite3
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Iterable
|
from typing import Any, Iterable, Optional
|
||||||
|
|
||||||
|
|
||||||
SCHEMA = """
|
SCHEMA = """
|
||||||
@@ -147,12 +147,30 @@ def _utc_timestamp() -> str:
|
|||||||
|
|
||||||
|
|
||||||
class MarketStore:
|
class MarketStore:
|
||||||
"""SQLite-backed market research warehouse."""
|
"""SQLite-backed market research warehouse. Use get_instance() for the singleton."""
|
||||||
|
|
||||||
|
_instance: Optional["MarketStore"] = None
|
||||||
|
|
||||||
|
def __new__(cls, db_path: Path | None = None) -> "MarketStore":
|
||||||
|
if cls._instance is not None:
|
||||||
|
if db_path is None or cls._instance.db_path == Path(db_path or get_market_db_path()):
|
||||||
|
return cls._instance
|
||||||
|
instance = super().__new__(cls)
|
||||||
|
cls._instance = instance
|
||||||
|
return instance
|
||||||
|
|
||||||
def __init__(self, db_path: Path | None = None):
|
def __init__(self, db_path: Path | None = None):
|
||||||
|
if getattr(self, "_initialized", False):
|
||||||
|
return
|
||||||
self.db_path = Path(db_path or get_market_db_path())
|
self.db_path = Path(db_path or get_market_db_path())
|
||||||
self.db_path.parent.mkdir(parents=True, exist_ok=True)
|
self.db_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
self._init_db()
|
self._init_db()
|
||||||
|
self._initialized = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_instance(cls, db_path: Path | None = None) -> "MarketStore":
|
||||||
|
"""Get the MarketStore singleton instance."""
|
||||||
|
return cls(db_path)
|
||||||
|
|
||||||
def _connect(self) -> sqlite3.Connection:
|
def _connect(self) -> sqlite3.Connection:
|
||||||
conn = sqlite3.connect(self.db_path)
|
conn = sqlite3.connect(self.db_path)
|
||||||
|
|||||||
@@ -226,7 +226,6 @@ async def run_with_gateway(args):
|
|||||||
)
|
)
|
||||||
runtime_manager.prepare_run()
|
runtime_manager.prepare_run()
|
||||||
set_global_runtime_manager(runtime_manager)
|
set_global_runtime_manager(runtime_manager)
|
||||||
register_runtime_manager(runtime_manager)
|
|
||||||
|
|
||||||
# Create market service
|
# Create market service
|
||||||
market_service = MarketService(
|
market_service = MarketService(
|
||||||
|
|||||||
@@ -13,15 +13,30 @@ from .registry import RuntimeRegistry
|
|||||||
_global_runtime_manager: Optional["TradingRuntimeManager"] = None
|
_global_runtime_manager: Optional["TradingRuntimeManager"] = None
|
||||||
_shutdown_event: Optional[asyncio.Event] = None
|
_shutdown_event: Optional[asyncio.Event] = None
|
||||||
|
|
||||||
|
# Lazy import to avoid circular dependency
|
||||||
|
_api_runtime = None
|
||||||
|
|
||||||
|
|
||||||
|
def _get_api_runtime():
|
||||||
|
global _api_runtime
|
||||||
|
if _api_runtime is None:
|
||||||
|
from backend.api import runtime as api_runtime_module
|
||||||
|
_api_runtime = api_runtime_module
|
||||||
|
return _api_runtime
|
||||||
|
|
||||||
|
|
||||||
def set_global_runtime_manager(manager: "TradingRuntimeManager") -> None:
|
def set_global_runtime_manager(manager: "TradingRuntimeManager") -> None:
|
||||||
global _global_runtime_manager
|
global _global_runtime_manager
|
||||||
_global_runtime_manager = manager
|
_global_runtime_manager = manager
|
||||||
|
# Sync to RuntimeState for consistency
|
||||||
|
_get_api_runtime().register_runtime_manager(manager)
|
||||||
|
|
||||||
|
|
||||||
def clear_global_runtime_manager() -> None:
|
def clear_global_runtime_manager() -> None:
|
||||||
global _global_runtime_manager
|
global _global_runtime_manager
|
||||||
_global_runtime_manager = None
|
_global_runtime_manager = None
|
||||||
|
# Sync to RuntimeState for consistency
|
||||||
|
_get_api_runtime().unregister_runtime_manager()
|
||||||
|
|
||||||
|
|
||||||
def get_global_runtime_manager() -> Optional["TradingRuntimeManager"]:
|
def get_global_runtime_manager() -> Optional["TradingRuntimeManager"]:
|
||||||
|
|||||||
4
frontend/test-results/.last-run.json
Normal file
4
frontend/test-results/.last-run.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"status": "failed",
|
||||||
|
"failedTests": []
|
||||||
|
}
|
||||||
1
reference/CoPaw
Submodule
1
reference/CoPaw
Submodule
Submodule reference/CoPaw added at 934cfce0a7
1
reference/Hyper-Alpha-Arena
Submodule
1
reference/Hyper-Alpha-Arena
Submodule
Submodule reference/Hyper-Alpha-Arena added at f137cff476
1
reference/openclaw
Submodule
1
reference/openclaw
Submodule
Submodule reference/openclaw added at 7b151afeeb
Reference in New Issue
Block a user