内容
资产管理gate](https://github.com/disin7c9/asset-management/actions/workflows/ci.yml/badge.svg)](https://github.com/disin7c9/asset-management/actions/workflows/ci.yml)
**简介:** `uvx --from git+https://github.com/disin7c9/asset-management asset-management --demo 一个一键命令设置,即可获得一个组合的跌幅。该投资组合于美元,且仅为股票/ETF的长期您需要自行记录。
**跟踪个人股票/ETF投资组合,并获取可审计的建议。Python计算所有数字;可选的AI提供叙述 — 但在结构上无法自行生成数字。 🔢 数字围栏
许多AI金融工具让模型生成数字。而在这里,模型只能放置`{{token}}`占位符:一个确定性的渲染器从验证替换数字,**如果模型自行输入一个数字,则拒绝述**:
```text模型写入 │ 得到
─────────────────────────────────────────────────────────────────────────────────────
"您的最大跌幅为 │您的最大跌-9.84%,溃疡指数为2%,
{{max}},溃疡 {{ulcer}} │ 说明骑行过程。"
说明骑较为平稳。 │ 每个数字都从中替换
如果模型自行输入一个拒绝整个叙述─────────────┼────────────────────────────────────────
"您的投资了12%,但恢复 │ (没有 不错 — 不 │ ✘ 拒绝 — 模型数字使整个注释无效 │ 简报不包含它
```
运行这两个过程 —实际的生产围栏,无密钥:`uv run python scripts/demo_fence.py🎁 您将 **跌幅优先简介**,您的实际持仓 — 跌幅多大,多长,哪些了 — 每个采样数据都有bootstrap置(回报是会计身份不带有置信区间 **确定性买卖建议**,针对您选择的目標都与生成建议的**命名规则**配对 — 您了解规则,而不是信任机器人。
- 可选的、围栏的**AI叙述**,以及只读的**Claude Desktop插件**(“与您的投资组合聊天”),基于相同的验证核心。
持仓**衍生**自仅追加的交易日志(日期,代码,操作,数量,价格,每行手续费)— 永远不会存储 — 因此相同的输入始终产生相同的输出。价格通过提供商回退(主要使用Yahoo Finance,次要使用,通过免费API密钥)以及磁盘缓存每个显示的数字都可以追溯到其无法诚实计算的窗口太短,无)打印为`n捏造的**股票分割自动调整份额计数与分割调整后的价格历史记录相因此在您的持有期内分割不会扭曲回报。
## 📑 目录
- [这里开始](#这里开始)
- [⚡ 60秒(捆绑投资组合,无需设置-60秒试用捆绑的假投资组合无需设置)
- [💵 使用您自己的资金 — 四步](#-使用您自己的资金--四步)
- [🔍 为什么您可以信任数字](#-为什么您可以信任数字)
- [🚫 不提供财务建议 — 结构性,不是作为免](#-不提供财务建议--结构性不是责声明)
- 正确性是的主张](#-正确性是您可以检查的主张)
- [🔬 验证 — 与两个独立工具协调](#-验证--与两个独立工具协调)
- [💬 与您的投资组合聊天 — Claude Desktop插件(只读MCP)](#-与您的投资组合聊天--claude-desktop插件只读mcp)
- [🛟 如果出现问题](#-如果出现问题)
- [📖 参考](#-参考)
- [💻 示例输出](#-示例输出)
- [🔁 再平衡模式](#-再平衡模式)
- [📈 回测详情](#-回测详情)
- [🔭 发现与精选宇宙](#-发现与精选宇宙)
- [📝 叙述(可选的纯语言摘要)](#-叙述可选的纯语言摘要)
- [🔑 配置 — 每个键都在一个地方](#-配置--每个键都在一个地方)
- 项目](#- - [🧪-开发)
- [📁 布局](#-布局)
- [🔒 隐私政策](#政策)
- [📜 许可证](#-许可证)
## 🚀 从这里开始
### ⚡ 60秒试用(捆绑的假投资组合,无需设置)
```bash
uvx --from git+https://github.com/disin7c9/asset-management asset-management --demo
```
或从克隆:`uv sync && uv run python -m app --demo`(需要Python 3.12和[uv](https://docs.astral.sh/uv/)。
**完整参观**(仍然是捆绑的书籍,约一分钟在线)— 以下两个命令从头到尾展示了工具的特征:提出一个预设目标,然后**验证**它与已知的60-40参考,并用每行背后的命名规则和每基金事实进行阈值带再平衡建议:
```bash
uvx --from git+https://github.com/disin7c9/asset-management asset-management --demo --allocate moderate --allocate-out demo_target.csv
uvx --from git+https://github.com/disin7c9/asset-management asset-management --demo --backtest --target demo_target.csv --benchmark 60-40 --rebalance bands --metadata
```
注意它**不**说的内容:裁决结果类似于“与60-40没有明显的跌幅差异;配对的bootstrap没有确认差距”当证据不足时 — 永远不会“击败基准”。当输出获得您的信任时,以下四个步骤将其指向您自己的资金。
### 💵 使用您自己的资金 — 四步
#### 步骤1 — 您的账簿(输入)
所有内容都源自一个交易日志。CSV格式是**Ghostfolio自己的CSV导入模式**(因此您在此处保留的账簿也可以直接导入Ghostfolio)— 列`Date, Code, DataSource, Currency, Price, Quantity, Action, Fee, Note`。`Action`是`buy`, `sell`, `dividend`, `fee`, `interest`, `deposit`, `withdraw`之一。现金流(`deposit`/`withdraw`)使用`CASH`代码,并在`Price`列中放置金额。**此工具仅限美元**(仅股票/ETF长期投资):`Currency`必须是`USD` — 非美元行会被错误拒绝。空的数字列单元格被视为零。非ISO日期会被明确错误拒绝。UTF-8 BOM被容忍。捆绑的示例([data/sample_data/transactions.csv](data/sample_data/transactions.csv))显示了每种行类型。
**已经使用[Ghostfolio](https://ghostfol.io)?** 直接指向Ghostfolio **JSON**导出(Portfolio → Activities → ⋯ → Export)— 加载器检测到它并直接读取,无需转换步骤。它读取活动(股息现金= `quantity × unitPrice`;Ghostfolio的UTC时间戳四舍五入到您的本地日期)并跳过非美元,加密和非证券(`ITEM`/`LIABILITY`)行,并发出警告(目前仅限美元,股票/ETF)。没有本地Ghostfolio帐户的经纪商可以运行社区转换器,如[Export-To-Ghostfolio](https://github.com/dickwolff/Export-To-Ghostfolio)(26个经→Ghostfolio JSON)。
```bash
uv run python -m app --book your.csv # 或ghostfolio-export.json — 自动检测 run python - --book your.csv-run # 预前:格式,事件,跳过的行和原因,
# 派生的持仓 — 提取价格
# 不会获取
```
**在gitignored `.env`中设置您的默认设置** 在仓库根目录 — `ASSET_BOOK=path/to/your.csv`(和可选的`ASSET_TARGET=path/to/target.csv`)— 裸`python -m app` 成为您的简介。显式标志始终优先。**没有无声内置默认设置**:如果没有`--book`或`ASSET_BOOK`,依赖于账簿的操作会出错,裸运行会打印提示 — 捆绑的示例是可选的(`--demo`),从不被假定。
#### 步骤2 — 预热缓存(一次)
核心是离线优先:价格来自磁盘缓存,在线时刷新。克隆后,首次填充:
```bash
uv run python -m app --book your.csv --warm # 您的股票代码 + 基准参考
uv run python -m app --book your.csv --warm full # + 约375-ETF 发现宇宙(—
# 仅在离线 --dis需要
```
之后--offline`运行和Claude Desktop插件完全缓存提供服务(`--cache-dir` / `ASSET_CACHE_DIR`覆盖位置)。
**可选但推荐:** 在`.env`中添加免费的[Tiingo](https://www.tiingo.com) API密钥 — `TIINGO_API_KEY=...` — 以启用第二个价格来源。Yahoo Finance偶尔会限制请求;,获取会回Tiingo,而不是报告。没有密钥,工具仅从Yahoo。
#### 步骤 选择目标
大多数决策功能(`--`,`--`,walk-forward都针对**目标 一个小的CSV,Weight`),您拥有并编辑。获取目标的三种方法,按您开始的位置:
已经持有投资 → `--dump-target写入您的**分配;编辑它以达到您想要的混合比例。(目标是**完整规范** — 参见[再平衡模式](#-模式),了解退出语义。)
- **从风险姿态开始**onboard`在询问三个简单时间范围/损失现金缓冲),并的预设;`--allocate conservative|moderate|aggressive`。保存时使用`--allocate-out。两者都在账簿的情况下**您的第一笔,每个角色都从中填写。您已经持有的角色会解析为*您的*缺失的精选宇宙中的ETF填充。
探索并自行构建 `--discover`轻仓的筛选`--screen QQQCHD`会根据您的账簿流动性,年龄,重叠以及它是否真正使您的最大跌幅多样化)评估候选资产。然后手动编写CSV。
还存在两种更简单的权重调整规则 — `--allocate`(1稳健基线)和`--allocate inverse_vol每个持有资产贡献大致相同的*风险*,而非相同金额;使用`--allocate-cap 0.30`限制单个)。**不**return-forecasting优化器(均值-方差 / max-Shar— 它们会过度拟合,因此在后续版本中为*edge*网关保留。
**在遵循目标之前验证:**
```bash
uv run python -m app --backtest --target target.csv --benchmark 60-40 # 或all-weather |```
模拟您的参考在它们上(名义10,000美元幅优先的腿),并添加一个**walk-forward保留判决shallower`eper` /conclusive` /ufficient` — 永远不会“击败”。溃疡指数**(整个窗口的痛苦 — 多和多长),并要求CDaR(部平均不矛盾,且配置信区间确认;跌幅作为背景报告,不作为决策 — 单一最坏事件在短期历史中杂,任何决定。当无法,它会说`clusive`,指出哪个门阻止了它。
**提议和行动是独立步骤**,强制执行allocate`/`--onboard`仅*提议*(并可选地写入文件),**不能与`--backtest`/`--rebalance`**在单个命令中组合。您审查文件,然后模拟订单 —命令都在其自己的。策略永远不会地变成交易。
#### 步骤4 — 每周简介
一个命令涵盖例行签到 — 状态简介,当一个违反时的建议操作,+基准裁决:
```uv run python - --book your.csv --backtest --targetbenchmark permanent --rebalance bands --metadata # + --narrate --save --send 自选
```
- 选择与您的姿态最接近的benchmark`参考(`60-40 `all-weatherpermanent- `bands`持有资产偏离(“5规则”)时才起作用,**--new-cash 在您存款的一周,请改用`--rebalance cash_flow_only-cash 500投资于低权重,从不卖出;对税收友好)。
- 面板是**可组合的** — 每个标志添加一个面板,它们堆叠(参见[参考](#-参考))。
同一个报告从一个构建中退出三种方式:stdout上的纯文本(始终),到/<asof`的markdown(save`),邮件(` `.env`RESEND_API_KEY` + `REPORT)。失败的接收崩溃运行报仍然打印被记录 — 但如果您**请求的**失败,进程退出,以便调度程序注意到周一的在cron上仅需执行此操作:cron
# 00 每个 — 发送简报并存档markdown。
# cron的PATH很小uv — 指向参见 `which uv`):
PATH=/home/you/.local/bin:/bin
8 *1 cd //asset-management && -m app your.csv -- --target targetbenchmark permanent --reb --metadata --save --send >> reports/c 2>&1
```
(cron仅机器开启才会触发L上任务调度器运行.exe`触发的替代方案工具读取的都在[配置](#-配置--每个键)中列在没有WSWindows上,以上均保持不变(`uv`自带`irm https://astral.sh/.ps1 | ie安装,克编写`.env`,运行)。只有调度器不同:
```powershell
# 上述cron行的Windows对应版本,从您的克隆。
# -StartWhenAvailable:机器在星期一醒来时过。
Register-ScheduledTask -Task-brief" `
-Trigger (cheduledTaskTrigger -DaysOfWeekAt 8:00am) `
-Settings (New-ScheduledTaskSettingsSet -StartWhenAvailable) `
-Action (New-ScheduledTaskAction -Execute "$env:USERPROFILE\.local\bin\uv.exe" `
-Argument "run python -m app --book your.csv --backtest --target target.csv --benchmark permanent --rebalancemetadata --send" -WorkingDirectory "C:\path\to\asset-management")
```
## 🔍 为什么您可以信任数字
### 🚫 不提供财务建议 — 结构性,不是作为免输出的**形式**使其成为描述而非建议:
-建议都与的**命名配对,从裸“买入X”;
- 每个采样的风险指标都带有**置信区间数据不足时显示inconclusive`insufficient`,`n/a`假装;
- 基准裁决仅显示ower` /eper` / `inconclusive`insufficient`** —表中没有“;
- 任何具有**优势**的主张必须在-forward(样本外)门控**通过后才能显示建议 — 仅限样本的数字被设计为拒绝;
- 工具是**只的:它从,AI也写入您的账簿。
### ✅ 正确您可以检查的主张
- [门控](.github/workflows/ci.yml) 在每个推送到`main`和每个PR时运行完整的测试套件 + `mypy --strict`+ruff — 顶部的徽章是门控,实时;
- 持有资产价值和损益与[Ghostfolio://ghostfol.io) **精确钱**,与quantstatsreconcile/RESULTS.mdile/RESULTS.md)Sharpe / Sortino / **精确到4位小数** 每个公式都写在[M](MATH.md)中;
-围栏是一个您可以自己测试的[`scripts/demo_fence.py`](_fence.py)。
### 🔬 与两个独立工具协调
数据上的数字与两个独立[`reconcile/`](reconcile/)中的测试框架)进行了交叉
- **ghostfolio** 重建持有资产、市场价值和损益日志完全匹配 **到一分钱**。
- **quantstats** 独回报率序列的夏普比率、索丁诺比率和最大跌幅四位小数** 匹配。
每个 回报率、跌幅系列(溃疡指数/CDaR)、风险调整比率、自举置信区间和分配/筛选数学 — 都在单一位置定义:[MATH.md](MATH.md)。
它们共同验证整个管道:ghostfolio确认持有资产/价值重建;quantstats确认风险/回报公式。完整的比较在[`reconcile/RESULTS.md`](reconcile/RESULTS.md)中。
```bash
uv run --with quantstats/reconcile_quantstats.py # 指标交叉检查 end-to-end (ghostfolio): 参见 reconcile/RESULT
```
## 💬 与您的投资组合聊天 — Claude Desktop 插件(只读MCP)
将您的投资组合暴露给AI助手(Claude Desktop,Claude Code等)作为**只读工具**,它可以调用这些工具,以便您在验证的核心中查看投资组合的最新数据,而不影响实际数据。服务器是**只读**的,没有写入工具,绑定到您的`ASSET_BOOK`账簿(无文件路径参数),并且**离线**,除了两个有界限的、可选择退出的获取操作:一个冷缓存**自动预热核心数据集**一次(您的股票代码 + 基准参考,大约30-60秒),以及筛选/提出一个未缓存的股票代码时按需获取。设置`ASSET_MCP_OFFLINE=1`以禁用两者(适用于**已经预热**的缓存;指向一个冷缓存时,它会降级为诚实的`n/a`)。八种工具:
- **`portfolio_summary`** — 持仓、盈亏、年化回报。
- **`risk_report`** — 回撤优先的风险:最大回撤(深度/日期/恢复)、溃疡指数、CDaR、夏普/索丁诺/卡尔玛比率,均带有bootstrap置信区间。
- **`rebalance_check`** — 根据您的`ASSET_TARGET`(建议买卖,拒绝超额配置部分缓存的账簿)。
- **`securities_facts`** — 每种持仓的已发布基金事实(费用率、资产管理规模、交易量、年龄、类别)。
- **`discover_gaps`** — 为您持仓比例≤3%的角色建议新的ETF(仅建议,需要`--warm full`)。
- **`screen_candidate`** — 根据您的账簿评估新的候选股票代码(多元化/成本/流动性/年龄/重叠,每个都有原因)。
- **`propose_allocation`** — 根据您的账簿和宇宙的战略目标,针对特定的姿态(保守/适度/激进)进行验证,并给出与参考资料相同的步行前进、溃疡优先的裁决 — 仅建议,数字来自核心,绝不推荐。
- **`starter_allocation`** — 新用户?回答三个简单风险问题 → 一个起始姿态及其验证提案(进入`propose_allocation`的 onboarding 路径)。
**安装(Claude Desktop):** 设置 → 开发者 → **编辑配置**,并添加:
```json
{
"mcpServers": {
"asset-management": {
"command": "uvx",
"args": ["--from",
"https://github.com/disin7c9/asset-management/releases/download/v2.11.4/asset_management-2.11.4-py3-none-any.whl",
"asset-management-mcp"],
"env": {
"ASSET_BOOK": "C:\\path\\to\\your\\transactions.csv",
"ASSET_TARGET": "C:\\path\\to\\your\\target.csv",
"TIINGO_API_KEY": "your-free-tiingo-key(可选二级来源)"
}
}
}
}
```
重启Claude Desktop。您需要将[uv](https://docs.astral.sh/uv/)添加到PATH中,除此之外无需其他操作 —
`uvx`自行解决Python和锁定依赖项。**第一次启动较慢**(它构建了一个约500 MB的环境:pandas / NumPy / PyArrow),所以请给它一分钟时间;之后的每次启动都只需几秒钟。第一次工具调用会一次性预热价格缓存(约30-60秒),该缓存存储在您的主文件夹中,因此它可以跨越重新安装。免费计划可用。该URL固定了一个发布版本 —
除非您升级,否则版本之间不会发生变化;要升级,请将版本号替换为[最新发布版本](https://github.com/disin7c9/asset-management/releases/latest)。
**每个`env`条目都是可选的** — 删除您不需要的条目。删除`ASSET_BOOK`以探索**捆绑的演示投资组合**,使用假数据。首先,`ASSET_TARGET`是`rebalance_check`比较您的持仓的对象(如果没有它,该工具会报错并给出提示)。`TIINGO_API_KEY`(免费账户)添加了当Yahoo限制访问时的第二个价格来源。较少见的情况:`ASSET_CACHE_DIR`(移动价格缓存),`ASSET_MCP_OFFLINE=1`(永不获取 — 对于已经预热的缓存)。**此处不放置LLM密钥**:读取这些工具的助手*是*叙述者;服务器本身从不调用模型。
**.mcpb 捆绑包 — 仅适用于Claude Code**。使用`uv run python scripts/build_mcpb.py` → `dist/asset-management-<version>.mcpb`构建它,并在设置 → 扩展程序中单击一次安装。它的工具在**Claude Code**中工作。它们在Claude Desktop的聊天窗口中**不**工作:Desktop不向模型提供来自**侧载**扩展程序的工具 — 它们出现在工具菜单中,保持其权限切换,并且根本不会被调用。
目录安装的扩展程序和配置注册的服务器都起作用,这就是为什么上面的配置路由是用于聊天的首选路由。
**在聊天中:** 打开**+**菜单,获取现成的启动器 — *投资组合检查*、*我的回撤是多少?*、*我应该再平衡吗?*、*填充我的空白*、*找到我的起始分配*、*提出一个姿态* — 每个都预加载了仅限数字的框架。服务器还发布`portfolio://guarantees`(其四个强制保证,版本,随代码发布):从同一个**+**菜单中附加它 —
或者,在允许模型直接读取资源的客户端中,只需询问“能否信任这些数字?”并从清单中回答,而不是临时编造。
### 🛟 如果出现问题
- **Claude 表示它只能看到一个工具,或根本看不到任何工具。** 转到设置 → **连接器** → *asset-management* 并打开工具。新建的服务器及其工具**被阻止**,而在权限提示中批准一个工具只会启用该工具。然后Claude会诚实地报告它看到的有限列表 — 它没有办法知道其他工具的存在,所以它会告诉你服务器“只有一个工具”。它有八个工具。
- **工具出现在菜单中,但Claude 从未调用它们。** 您安装了`.mcpb`捆绑包。Claude Desktop的聊天窗口不向模型提供**侧载**扩展程序的工具 — 菜单和权限切换来自扩展程序本身,所以一切看起来都已连接,而模型永远不会被告知工具的存在。删除扩展程序并使用上面的配置路由。
- **服务器根本不出现。** Claude Desktop 解析`"command"`在您的PATH中并找不到`uvx`。安装[uv](https://docs.astral.sh/uv/)并重启Desktop,或将绝对路径放在`"command"`中(Windows:`C:\Users\<you>\.local\bin\uvx.exe`)。
- **它在第一次启动时断开连接。** 首次启动时正在构建环境(~500 MB)。给它一分钟,然后重启Claude Desktop。之后的启动仅需几秒钟。
- **第一次启动因`os error 32`(“另一个进程正在使用该文件”)而失败。)** Windows:在uv构建环境时,另一个进程 — 通常是防病毒扫描器 — 暂时占用了uv缓存中的一个新写入文件,安装程序就会丢失竞争。自己在终端中运行`uvx`命令(如果再次失败,只需重新运行 — 那里的重试操作不会带来任何成本)。当它保持沉默时,环境就已构建:Ctrl-C,重启Desktop。之后的每次启动都会重用已构建的环境,绝不会竞争。
- **每个数字都返回`n/a`。)** 价格缓存是冷的,并且`ASSET_MCP_OFFLINE=1`禁止获取数据以预热缓存。删除该变量,或从CLI预热缓存一次:`uvx --from git+https://github.com/disin7c9/asset-management asset-management --book your.csv --warm`。
- **(仅`.mcpb`)`No MCP config found for extension … skipping`。)** Desktop在**保存**配置表单之前不会启动服务器 — 而保存按钮处于禁用状态,直到您更改某些内容。切换任意字段,保存,重启。
或直接运行服务器/使用Claude Code注册:
```bash
uv run python -m app.mcp_server # 通过stdio提供服务(在.env中设置ASSET_BOOK)
asset-management-mcp # 与已安装的入口点相同的服务器
claude mcp add asset-management -- uv run python -m app.mcp_server # 注册,然后使用/mcp
```
服务器本身不运行LLM — 助手调用它;这不是财务建议。
## 📖 参考
报告是**可组合面板**,而非专属模式 — 组合标志,面板堆叠。每个操作需要:
| 操作 | 需要 | 执行操作 |
|---|---|---|
| 状态简报(默认) | `--book` | 您的持仓 + 回报 + 回撤/风险 |
| `--rebalance MODE` | `--book` + `--target` | 买卖建议朝向目标(`--new-cash`调整存款大小) |
| `--allocate RULE` | `--book` | 提出目标 — 重新权衡您的持仓(`equal_weight`/`inverse_vol`)或构建战略角色模板(`conservative`/`moderate`/`aggressive`);写入`--allocate-out` |
| `--onboard` | `--book`(或`--demo`) | 新用户的步骤0:回答终端中的3个简单风险问题 → 匹配的姿态自动构建其`--allocate`预设(仅建议;使用`--allocate-out`保存) |
| `--dry-run` | `--book`(或`--demo`) | 预览导入前:检测格式,解析事件,跳过/标记的行和原因,以及它们得出的持仓 — 不获取任何内容,不计算简报 |
| `--metadata` | `--book` | 每种持仓的已发布基金事实(费用率,资产管理规模,交易量,年龄,类别),缓存7天 |
| `--screen TICKERS` | `--book` + 价格 | 评估新的候选股票代码与您的账簿:多元化(包括您的红色天数 + 最坏回撤),成本,流动性,年龄,集中度,杠杆/反向自动拒绝,持仓重叠重复 — 每个判决都有其原因。添加`--target`以进行**步行前进角色检查**:5%的袖子是否减少了回撤痛苦(溃疡指数,并带有CDaR检查)?“不确定”表示阻止它的门槛。仅建议;PASS是“明智,便宜,流动,真正不同”,绝不是预测 |
| `--discover [roles]` | `--book` + 价格 | 建议**新的**ETF用于您持仓比例≤3%的角色,通过相同的筛选 — 仅建议(参见[发现](#-发现--精选宇宙)) |
| `--backtest` | `--target` | 名义再平衡与买入并持有 — **无`--book`**;仅打印模拟结果 |
| `--backtest --benchmark REF` | `--target` | 验证目标与规范参考(`60-40` / `all-weather` / `permanent`)— 优先考虑回撤的腿 + 步行前进,溃疡指数优先的保留裁决 |
| `--narrate` | `--book` + 一个LLM密钥 | 简洁的语言**摘要**在简报顶部;模型仅写入文字,每个数字被替换并从核心验证(可选,默认为关闭 — 参见[叙述](#-叙述-可选的简洁语言摘要)) |
所有标志,分类:
```bash
# 输入和缓存
uv run python -m app --demo # 零设置测试驱动程序,使用捆绑的示例账簿
uv run python -m app --book your.csv # 您的账簿(CSV或Ghostfolio JSON,自动检测)
uv run python -m app --book your.csv --dry-run # 预览导入 — 不获取任何内容
uv run python -m app --book your.csv --warm # 一次性:填充离线缓存(添加`full`以获取整个宇宙)
uv run python -m app --book your.csv --offline # 从磁盘缓存提供服务;无网络
uv run python -m app --book your.csv --no-prices # 仅持仓 + 实现盈亏(无网络)
uv run python -m app --book your.csv --cache-dir /some/dir # 覆盖缓存位置
# 面板(自由堆叠)
uv run python -m app --book your.csv --no-risk # 跳过持仓回撤/风险面板
uv run python -m app --book your.csv --metadata # + SECURITIES面板(基金事实)
uv run python -m app --book your.csv --screen QQQM,SCHD # 评估新的候选股票代码
uv run python -m app --book your.csv --screen SCHD --target t.csv # + 步行前进角色检查
uv run python -m app --book your.csv --discover # + 发现面板(填充空白的ETF)
uv run python -m app --book your.csv --narrate # + 受限的简洁语言摘要
# 目标(仅建议)
uv run python -m app --book your.csv --dump-target target.csv # 写入您的**当前**分配
uv run python -m app --book your.csv --allocate moderate --allocate-out t.csv # 战略预设
uv run python -m app --book your.csv --allocate inverse_vol --allocate-out t.csv # 重新权衡持仓
uv run python -m app --demo --onboard # 3个问题测验 → 预设
# 实际操作和验证(单独的命令,设计如此)
uv run python -m app --book your.csv --rebalance to_total --target target.csv # 朝向目标的建议
uv run python -m app --book your.csv --rebalance cash_flow_only --target target.csv --new-cash 1000
uv run python -m app --backtest --target target.csv # 名义回测 — 仅目标,无--book
uv run python -m app --backtest --target target.csv --benchmark 60-40 # + 参考比较和裁决
uv run python -m app --book your.csv --rebalance bands --backtest --target target.csv # 面板堆叠
# 交付
uv run python -m app --book your.csv --save # 还写入reports/<asof>.md(markdown)
uv run python -m app --book your.csv --send # 还通过Resend将简报以HTML形式发送
```
### 📈 回测详情
`--backtest --target T.csv` 运行一个**名义上的 $10,000**的历史模拟,对该目标进行模拟,并打印一个**回测**面板,比较**再平衡**(按 `--rebalance-every {monthly,quarterly,annually}` 调度,默认为季度)与**买入并持有** — 先按回撤(最大回撤、溃疡指数、CDaR — 每个都有bootstrap CI),然后是夏普比率/索尔蒂诺比率和回报。这是一个**名义上的**模拟:它以目标权重在所有股票都有价格的最早日期(`--backtest-start` 可覆盖)开始,测试**策略**,与实际购买时机无关。标记为**历史模拟,非预测**。
固定的再平衡策略不适合任何参数,因此整个历史都是外生干净的(无需过度拟合)。**前向选择**机制 — 仅在策略**搜索**(调整参数或从候选人中选择:优化器或**边缘**时机策略)时需要一次 — 被故意推迟;**纪律与边缘门控**强制任何未来的边缘策略必须通过前向回测,然后才能提出建议。今天的再平衡模式都是**纪律**,因此它们可以自由建议。
使用 `--benchmark` 时,保留判决通过三个命名门控:**溃疡收益**必须清除噪声裕度,**CDaR**(最差尾部平均值)可能相等但不得矛盾方向,并且**配对移动块bootstrap CI**必须确认 — 否则为`不确定`,并在原因中命名阻塞门控。最大回撤和波动率作为上下文报告,不进行投票:单个最坏事件是极端值统计数据,在短历史记录中过于嘈杂,无法做出任何决定。
### 🔭 发现与精选宇宙
`--discover` 将您的持仓映射到角色(美国大型股、新兴市场、TIPS、REIT 等),找到您持仓中占比 ≤3% 的角色,从**精选宇宙**(捆绑 `app/data/universe.csv`,约 375 个低成本 ETF)中选取最大的基金,并通过与 `--screen` 相同的筛选器 — 打印一个发现面板,每个候选人都有其判决(通过/警告/失败)及其原因。 `--discover reit,tips` 限制角色;添加 `--narrate` 以获取一个有围栏注释的排名,按角色适合度排序。 通过表示“稳健、廉价、流动且与您持有的股票真正不同” — 永远不是预测。
宇宙是**自动构建**(和可刷新的)— 无需手动维护:
```bash
uv run python scripts/build_universe.py --auto --out app/data/universe.csv
```
它从分类器中提取每个资产类别中最大的美国ETF(按基金规模,而不是过去回报 — 追求绩效正是该策略避免的陷阱),删除杠杆/反向的,并为分类器无法隔离的少数类别保留一小部分精选集。 在 `.env` 中将 `--discover` 指向您自己的列表,设置 `ASSET_UNIVERSE=path/to/universe.csv`。
### 📝 叙述(可选的纯语言摘要)
`--narrate` 在简报顶部添加一个简短的**摘要**,用纯中文描述 — 您的回撤、风险和回报,以句子形式表达。 它是**可选的,默认关闭**,并且它是构建的,以便语言模型永远不会在您的简报中放置错误的数字:模型只会用 `{{placeholder}}` 令牌编写散文,而工具会从其核心替换**验证**的数字 — 如果模型尝试自己编写任何数字或命名不存在的数字,则拒绝整个摘要。 文本由模型编写;**每个数字都是工具的**,并且该块由生成它的模型标记。 相同的围栏叙述了发现面板( `--discover --narrate`:模型按角色适合度排名和解释筛选的候选人,从不预测)和基准判决( `--backtest --benchmark … --narrate`)。 它是描述,而不是财务建议。
您在 `.env` 中提供您自己的LLM密钥 — 除非您打开,否则不会发送任何内容:
```bash
ASSET_NARRATE_PROVIDER=anthropic # 或:openai(任何OpenAI兼容的端点)
ASSET_NARRATE_MODEL=claude-haiku-4-5
ASSET_NARRATE_KEY=sk-...
# 对于提供者=openai,还需要设置端点(需要https;http仅限localhost):
ASSET_NARRATE_BASE_URL=https://api.groq.com/openai/v1
ASSET_NARRATE_TIER=paid # 免费 | 付费 | 本地 — 隐私控制(见下文);默认为免费
```
**隐私控制**。`tier` 控制离开您的机器的内容。 在 **`free`**(默认 — 来自提供商的免费层级可能会在您的输入上进行训练)上,只发送**粗略的质量带**(“中等”,“稳健”);您的确切美元金额、回报和日期保留在本地并在本地填写。 在 **`paid`**(具有合同约束的提供商不会在您的数据上进行训练)上,发送确切的数字以获取更丰富的措辞。 第三个层级, **`local`**,适用于在您自己的机器上运行的模型(Ollama / llama.cpp 在 `http://localhost` — 也适用于 `::1` 或 `host.docker.internal`):它也会发送确切的数字,因为没有任何内容会离开机器,并且仅针对真正的本地端点进行验证(否则它会回退到 `free`)。 隐私控制**安全失败**:仅明确的 `paid` 或 `local` 才会发送确切的值 — 空白或拼写错误的层级仍保留在 `free`,并且在 `free` 上,工具会记录一行提醒,即提供商可能会对发送的内容进行训练。 如果没有配置叙述,或者模型调用失败,简报将直接打印,没有摘要。
### 🔑 配置 — 所有密钥都在一个地方
所有配置都是环境变量。 从checkout运行, 在gitignored `.env` 中设置它们; 通过 `uvx` 运行(无需checkout读取 `.env`),设置相同的名称为实际环境变量 — 或在Claude Desktop配置的 `env` 块中。 显式标志始终生效。
```bash
# 您的书籍 + 目标(步骤1和3)
ASSET_BOOK=data/my_data/transactions.csv
ASSET_TARGET=data/my_data/target.csv
# 价格 — 当Yahoo Finance限速时的可选免费第二来源(步骤2)
TIINGO_API_KEY=...
# --send 的邮件投递(步骤 4)
RESEND_API_KEY=...
REPORT_TO=you@example.com
# REPORT_FROM=briefs@yourdomain.com # 可选;默认为 Resend 的注册发件人
# --narrate 的叙述(可选 — 您自己的LLM密钥;参见上面的叙述)
ASSET_NARRATE_PROVIDER=anthropic # 或:openai(任何OpenAI兼容的端点)
ASSET_NARRATE_MODEL=claude-haiku-4-5
ASSET_NARRATE_KEY=sk-...
# ASSET_NARRATE_BASE_URL=https://... # 提供者=openai
# ASSET_NARRATE_TIER=free # 免费(默认:仅粗略频段离开)| 付费(确切数字)| 本地
# MCP 插件专用
# ASSET_MCP_OFFLINE=1 # 永不获取 — 用于预热缓存
# 很少需要
# ASSET_CACHE_DIR=/somewhere/else # 移动价格缓存
# ASSET_UNIVERSE=path/to/universe.csv # 您自己的发现宇宙
```
这里不需要任何内容:每个需要密钥的功能都会说明,当您调用它时,会干净地降低功能。
## 🔧 项目
### 🧪 开发
```bash
uv run pytest # 单元测试 + 属性测试 + 回归测试
uv run mypy app/ # 严格的类型检查
uv run ruff check app/ tests/ # 整理
uv run python scripts/build_mcpb.py # 打包 Claude-Desktop 插件 → dist/asset-management-<v>.mcpb
```
### 📁 布局
```
asset-management/
├── app/
│ ├── events.py CSV / Ghostfolio-JSON → 类型事件列表
│ ├── derive.py 事件 → 持仓 + 成本基数 + 实现损益
│ ├── corporate_actions.py 分割调整原始股数(股票分割)
│ ├── prices.py 多源价格获取(最新 + 历史 + 分割)具有出处 + 缓存
│ ├── metadata.py 已发布基金事实(费用比率、资产管理规模、交易量、年龄、持仓)+ 缓存
│ ├── returns.py 事件 + 价格 → 股权曲线、真实时间加权回报、修正迪茨
│ ├── risk.py 回撤家族(最大回撤 / 溃疡指数 / CDaR)+ 夏普 / 索尔蒂诺 / 卡尔玛与bootstrap CI
│ ├── strategy.py 持仓 + 目标 → 命名买卖建议(再平衡模式)+ 边缘门控
│ ├── allocate.py 选择目标:等权重 / 逆向波动 + 风险姿态预设 + 每项资产上限
│ ├── onboard.py 步骤0风险测验(纯粹):3个问题 → 保守 / 中等 / 激进姿态
│ ├── screen.py 判断新的候选股票代码(分散投资 / 成本 / 流动性 / 年龄 / 重叠)
│ ├── backtest.py 名义模拟 + 前向回测角色/基准判决(溃疡指数优先)
│ ├── pipeline.py 共享书籍→价格→回报→风险捆绑(cli + mcp_server)+ 缓存预热 + --demo 书籍
│ ├── report.py 建议 + 回测 + 状态 + 价格 + 回报 + 风险 → ReportData → 文本/降价/HTML
│ ├── narrate.py 围栏叙述:验证数字 → {{token}} 散文 → 摘要(纯粹;数字不能是模型的)
│ ├── llm.py 可选的叙述后端(OpenAI兼容 + Anthropic);失败关闭,启用需配置
│ ├── email.py 通过 Resend 发送 HTML 简报(--send)
│ ├── cli.py argparse + 条目组成 + 投递路由 + 结构化运行日志
│ ├── mcp_server.py 读取 stdio MCP 服务器:8 个工具超过核心(离线;一次性冷调用自动预热,ASSET_MCP_OFFLINE=1 退出)
│ ├── universe.py 精选 ETF 宇宙加载器(候选人 + 角色); app/data/universe.csv,自动构建
│ ├── discover.py 书籍 → 角色差距 → 每个角色的顶级 AUM 候选人进行筛选(--discover,仅建议)
│ ├── log_config.py 日志设置
│ ├── __main__.py python -m app
│ └── __init__.py
├── tests/ 自动化套件(单元测试,属性测试,回归测试)— 离线,每次更改都会运行
├── reconcile/ 手动与外部工具进行交叉验证(ghostfolio,quantstats)
├── scripts/ build_universe.py(刷新ETF宇宙)· build_mcpb.py(Claude-Desktop 包)· demo_fence.py(戳围栏)
├── .github/ 网关:ruff + mypy --strict + pytest 在每次推送到 main + 每个PR
├── pyproject.toml 依赖项,mypy/ruff 配置
└── README.md
```
<a id="privacy-policy"></a>
## 🔒 隐私政策
该工具完全在您自己的机器上运行。 **它没有后端,没有帐户,也没有遥测** — 作者永远不会收到任何数据。
- **它收集的内容**。 没有。 您的交易日志,派生持仓和价格缓存仅在您的计算机上读取和写入,在您传递的路径上(`--book`, `--cache-dir`, 或 `ASSET_BOOK` / `ASSET_CACHE_DIR`)。 不会上传任何数据,也不会发出任何使用数据,崩溃报告或分析。
- **离开您机器的内容,仅限以下内容**。 (1)**价格和基金数据请求** — 股票代码发送到 [Yahoo Finance](https://finance.yahoo.com) 和(如果您设置 `TIINGO_API_KEY`)到 [Tiingo](https://www.tiingo.com),以获取报价,历史记录,分割和已发布的基金事实。 仅股票代码 — 永远不会发送您的数量,成本基数或余额。 (2)**叙述**, `--narrate`,默认情况下**关闭**:如果您打开它并提供您自己的LLM密钥,则投资组合**数字**发送到您选择的提供商(OpenAI兼容或Anthropic)以编写成散文。 `ASSET_NARRATE_TIER` 拨盘控制发送的详细程度; `local` 保留在您的机器上。 关闭它,不会联系任何LLM。
- **存储和保留**。 价格缓存位于 `.asset-management/prices` 在您的主文件夹(或 `ASSET_CACHE_DIR`)并持续到您删除它。 使用 `--save` 编写的报告转到 `reports/`。 所有内容都是您拥有的普通文件;删除文件夹,数据就会消失。 作者不保留任何副本,也无法访问。
- **第三方共享**。 没有。 作者不共享任何内容,因为作者没有任何内容。 发送到Yahoo,Tiingo或您选择的LLM提供商的数据受该提供商自己的隐私政策约束。
- **MCP服务器**。 只读,绑定到您的配置的书籍,无文件路径参数和写入工具。 它执行两个有界限的,退出网络获取(一次性冷缓存预热和按需获取,当您筛选未缓存的股票代码时); `ASSET_MCP_OFFLINE=1` 禁用两者。 它不会发送任何内容到其他地方。
- **联系**。 在 [github.com/disin7c9/asset-management/issues](https://github.com/disin7c9/asset-management/issues) 上打开一个问题。
## 📜 许可证
[AGPL-3.0-or-later](LICENSE)。 免费使用,修改和自我托管 — 包括商业用途。 一个条件: 如果您分发修改后的版本,或为他人运行网络服务,您必须在相同的许可证下发布您的修改后的源代码。 (与Ghostfolio使用的许可证相同。)
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器