[project] name = "openinvest" version = "0.34.0" description = "Investment runtime built for AI agents — 4-role LLM investment committee, portfolio ledger, decision accounting, MCP server" readme = "PYPI_README.md" license = "MIT" keywords = ["investing", "llm", "agent", "mcp", "portfolio", "trading-journal", "investment-committee", "claude"] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Financial and Insurance Industry", "Intended Audience :: Developers", "Topic :: Office/Business :: Financial :: Investment", "Programming Language :: Python :: 3.13", "Operating System :: POSIX :: Linux", "Operating System :: MacOS", ] requires-python = ">=3.13" dependencies = [ "ddgs>=9.10.0", "yfinance>=0.2.66", "python-dotenv>=1.0.1", "pandas-stubs~=2.3.3", "markdown>=3.10", "requests>=2.32.5", "beautifulsoup4>=4.14.3", "lxml>=6.0.2", "pandas>=2.3.3", "python-frontmatter>=1.1.0", "apscheduler>=3.11.2", "websockets>=15.0.1", "fastapi>=0.115", "uvicorn[standard]>=0.32", "croniter>=6.2.2", "openai>=1.45", # SDKAgent 直接走 OpenAI 兼容客户端(MiMo/DeepSeek/千问…,按 LLM_MODEL) "optuna>=4.0", # 阶段 4 RL:Bayesian Optimization 搜参 "feedparser>=6.0.10", # 事件层 RSS 源(Reuters/BBC/FT/财新 免费 feed) "sqlite-vec>=0.1.6", # 事件层向量精排(SQLite 扩展,不需要独立向量库) "mcp>=1.28.1", "akshare>=1.18.64", ] [project.urls] Homepage = "https://github.com/longsizhuo/openInvest" Documentation = "https://github.com/longsizhuo/openInvest/tree/main/docs/wiki" Repository = "https://github.com/longsizhuo/openInvest" Issues = "https://github.com/longsizhuo/openInvest/issues" Changelog = "https://github.com/longsizhuo/openInvest/blob/main/CHANGELOG.md" [project.scripts] openinvest = "openinvest.cli:main" openinvest-mcp = "openinvest.connectors.mcp_server:main" openinvest-web = "openinvest.connectors.web_api.__main__:main" [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = ["src/openinvest"] [tool.hatch.build.targets.sdist] # 只打包源码 + 元数据——默认会把整仓(docs/static/experiments,20MB)都塞进 sdist only-include = ["src/openinvest", "PYPI_README.md", "LICENSE", "pyproject.toml"] [dependency-groups] dev = [ "pytest>=9.0.3", "httpx>=0.27", "import-linter>=2.0", # 防 entry 层直调 core 原语漂移(见 ADR / CLAUDE.md "分层契约") ] # ============================================================================ # Import Rules(防漂移) # ============================================================================ # 强制分层:entry (jobs / connectors / scripts) 必须走 service layer # (core.committee_runner) 调委员会,不许直接 import core.committee 的 run_committee # 跳过 wealth_context_view / event_brief 等共享 input loader。 # # 跑: lint-imports --no-cache(grimp 缓存对 src/ editable 布局有 bug:缓存路径下 # 函数级 import 边丢失 → ignore 报 No matches。CI 已固定 --no-cache) # CI 已配(.github/workflows/ci.yml smoke section) # ============================================================================ [tool.importlinter] root_packages = ["openinvest", "scripts"] [[tool.importlinter.contracts]] name = "Entry 不直接调 run_committee(必经 service layer / shared loaders)" type = "forbidden" source_modules = ["openinvest.jobs", "openinvest.connectors", "openinvest.skill_cmds", "openinvest.cli", "scripts"] forbidden_modules = ["openinvest.core.committee"] # 只查直接 import;committee_runner 作为 service layer 合法转手 import core.committee allow_indirect_imports = "true" # allow list: 这些是合法直调(用 shared loader, 或者 daily_report 已经显式 prep) ignore_imports = [ # backtest_committee 是研究用,跟 production 委员会不共享 service layer "scripts.backtest_committee -> openinvest.core.committee", # full_validation 是开卷下限验证(研究用),需 patch core.committee.debate._persist 防污染 # (committee 拆包后 _persist 搬进 debate 子模块,import 目标随之变 core.committee.debate) "scripts.research.full_validation -> openinvest.core.committee.debate", ] [[tool.importlinter.contracts]] name = "Entry 不绕过 committee_runner 直调 runner 层(issue #179 P2:文档契约机器化)" type = "forbidden" source_modules = ["openinvest.jobs", "openinvest.connectors", "openinvest.skill_cmds", "openinvest.cli", "scripts"] forbidden_modules = ["openinvest.core.runner"] allow_indirect_imports = "true" ignore_imports = [ # full_validation 研究件需 patch session 层防污染真实 memory(与上一契约的例外同源) "scripts.research.full_validation -> openinvest.core.runner.session", ] [[tool.importlinter.contracts]] name = "计算层纯度:calc + 域绑定纯模块禁 import 内部 IO 模块(ADR-026;外部包 yfinance/requests + 时钟禁令走 CI AST 守卫)" type = "forbidden" source_modules = [ "openinvest.calc", "openinvest.jobs.daily_report_builder", "openinvest.jobs.pnl_render", "openinvest.jobs.review_calc", "openinvest.jobs.dreaming_calc", "openinvest.core.committee.cio_parse", "openinvest.core.committee.debate_calc", "openinvest.core.runner.intervention_rules", "openinvest.core.runner.event_format", "openinvest.core.decision_calc", "openinvest.core.schemas", ] forbidden_modules = [ "openinvest.db", "openinvest.services", "openinvest.connectors", "openinvest.utils.fx", "openinvest.utils.quotes", "openinvest.utils.exchange_fee", "openinvest.utils.gold_price", "openinvest.core.portfolio_manager", "openinvest.core.memory_store", "openinvest.core.benchmarks", "openinvest.capabilities", ] # 只封直连;daily_report_builder → utils.portfolio_summary → utils.fx 这类 # 函数级间接边放行(间接洗白靠 grep 守卫 + review 兜,见 ADR-026) allow_indirect_imports = "true" # 已删的孤儿 dep: # - duckduckgo-search: 被 ddgs 取代 # - langgraph: grep 全仓零引用 # - alpha-vantage: grep 全仓零引用 # - langchain / langchain-chroma / langchain-community / langchain-openai # (P1-4, 2026-05): 唯一用户是 agents/agent.py + scripts/diagnose.py,已被 SDKAgent 替代 # - chromadb: 只 agents/agent.py 用 (跟 langchain 一起删)