内容
<div align="center">
# 🪙 投注投资
### 连接托斯证券开放 API 与 AI·量化交易的开源项目
小数·速率限制·幂等性全部正确处理的 **SDK** + 向 LLM 提供账户 **安全**托管的 **MCP 服务器**



[](https://github.com/ongjin/tossinvest/actions/workflows/ci.yml)


</div>

> ⚠️ **非官方客户端** — 与托斯证券无关,与商标/背书无关。托斯开放 API 需要在 WTS `设置 > Open API` 中 발급密钥(限额·政策可能会在未预先通知的情况下更改)。但是,我们设计了可以在没有实时密钥的情况下进行全部制作、测试和演示的功能(纸质模式 + 模拟)。
---
## 一句话总结
- **量化交易者** → `pip install pytossinvest`,直接在 Python 中查询余额和下单。 *(SDK · MIT)*
- **交给 AI** → 将 MCP 客户端(Claude Desktop·Cursor)与 `pytossinvest-mcp` 连接,实现 *"查看我的余额 / 购买三星电子 5 股 / 分析汇率趋势"* 等功能。 *(MCP 服务器 · Apache-2.0)*
边界在 **SDK ↔ MCP** 之间清晰划分。量化交易者只需使用 SDK,而 AI 用户则额外获得安全模型。
---
## 为什么又要创建一个客户端?
自动生成的包装器无法阻止托斯 API 的 *陷阱*。所以我们手动、正确地实现了:
| | |
|---|---|
| 💸 **金额绝对不是浮点数** | 金额·数量全部使用字符串/`Decimal`。浮点数进入即报错 — 避免四舍五入导致的 1 元钱误差。 |
| 🚦 **客户端速率限制器** | 分组令牌桶 + **9 点开市 10 分钟 ORDER/ORDER_INFO 削减(6→3)** 反映。 **`X-RateLimit-*` 头部用于桶同步**(头部为准)+ **429 有限重试**(`Retry-After`/退避+jitter,5xx·超时不重试)。 |
| 🔁 **幂等性** | 自动管理 `clientOrderId` — 即使网络中断导致无法收到响应,也能使用相同键重试,防止 **重复订单**。 |
| 🧩 **错误按 `code` 分支** | 即使 `message` 为空也 OK。服务器 **添加未知代码/enum 也不会崩溃**。 |
| 🔐 **令牌生命周期管理** | 令牌过期前更新·内存缓存,`401 expired-token` 时一次重新颁发后重试。 |
| ✅ **无需实时密钥即可运行** | `git clone && uv sync && pytest` → **238 个测试** 通过。贡献门槛为 0。 |
---
## 🔒 核心 — 向 LLM 提供证券账户的 **安全**托管
这是真正的关键点。 **"如果 AI 擅自操作我的账户怎么办?"** 我们在服务端设置了防护栏,而不是依赖客户端信任。

1. **模式门控 — 默认安全模式。** `read_only`(完全不允许下单) / **`paper`(默认 · 本地模拟成交,零实际订单)** / `live`(实际订单)。`live` 模式需要同时设置 `TOSSINVEST_MODE=live` **和** `TOSSINVEST_ALLOW_LIVE=1` 才能启用。仅更改模式不会发生任何事情(fail-closed)。
2. **2 步下单 — 人在环中。** `preview_order` 检查防护栏并颁发 **短时有效的令牌**。`place_order` 没有该令牌 **直接拒绝**。LLM 不能直接连续发送预览和下单指令。我们同样对修改订单(`modify_order`)进行了相同的令牌校验。
3. **防护栏 — 适用于 paper 和 live 模式。** 每日累计金额上限(**按币种区分** — KRW/USD 分开) · 允许/拒绝特定股票 · **大额交易需要显式确认**(KRW 1 亿 / USD $100k↑) · **硬上限立即拒绝**(KRW 30 亿 / USD $3M↑) · 交易时间限制(live)。
> **不变式:** 所有成交路径 **必须** 通过防护栏。令牌仅在 `preview_order` 时颁发,通过防护栏后立即失效。没有任何绕过路径。
---
## 2 步下单流程 — preview → place,以及幂等性

令牌 **仅在成功时消耗**。如果 `place_order` 在途中失败,令牌仍然有效,可以使用相同的 `clientOrderId` 安全重试 — 不会发生 **重复成交**。如果成功,令牌立即失效,防止重复下单。
---
## 快速开始
### SDK — 直接在 Python 中使用
```python
from pytossinvest import TossInvestClient
with TossInvestClient(client_id="...", client_secret="...") as c:
c.get_accounts() # accountSeq 自动缓存(ACCOUNT 1/s)
prices = c.get_prices(["005930"])
print(prices[0].last_price) # Decimal("70000") — 绝对不是浮点数
# 下单使用字符串-decimal + 幂等性(clientOrderId 自定义)
c.place_order(symbol="005930", side="BUY", order_type="LIMIT",
price="70000", quantity="10", client_order_id="my-001")
```
### MCP — 连接到 Claude Desktop
`claude_desktop_config.json`:
```json
{
"mcpServers": {
"tossinvest": {
"command": "uv",
"args": ["run", "--directory", "/path/to/tossinvest",
"--package", "pytossinvest-mcp", "pytossinvest-mcp"],
"env": {
"TOSSINVEST_MODE": "paper",
"TOSSINVEST_CLIENT_ID": "...",
"TOSSINVEST_CLIENT_SECRET": "..."
}
}
}
}
```
默认为 `paper` 模式,无实际订单 — 可以放心尝试 *"查看三星电子 10 股行情"* 等指令。如需切换到实际订单,需设置 `TOSSINVEST_MODE=live` 和 `TOSSINVEST_ALLOW_LIVE=1`。
> ⚠️ **不建议将 live 模式与自动批准的 MCP 客户端一起使用。** preview→place 2 步流程依赖 **人为审批每个调用**。如果客户端自动批准,LLM 可能会在一步中连续发送预览和下单指令,导致问题。我们提供了 `pytossinvest-mcp` 的 `LIVE_CONFIRM_MIN_DELAY_SEC` 来增加额外防护。
---
## 模式一览
| 模式 | 下单 | 行为 | 启用方式 |
|---|:---:|---|---|
| `read_only` | ✗ | 仅读取,不允许下单 | `TOSSINVEST_MODE=read_only` |
| **`paper`** *(默认)* | ○ | 模拟成交,零实际订单 | (默认值) |
| `live` | ○ | 实际订单 | `MODE=live` **+** `ALLOW_LIVE=1` |
## MCP 工具(14 个)
- **读取(始终):** `get_accounts` · `get_holdings` · `get_quote` · `get_candles` · `get_stock_info` · `get_market_info` · `list_orders` · `get_order`
- **写入(paper·live):** `get_order_readiness` · **`preview_order` → `place_order`** · **`preview_modify` → `modify_order`** · `cancel_order`
所有限额·股票 allow/deny·起始资金等均可通过环境变量调节 → [`pytossinvest-mcp/README.md`](pytossinvest-mcp/README.md)。
---
## 一个仓库,两个包
| 包 | 角色 | 许可证 | 依赖 |
|---|---|:---:|---|
| [`pytossinvest`](pytossinvest/) | 托斯开放 API Python SDK | **MIT** | — |
| [`pytossinvest-mcp`](pytossinvest-mcp/) | 附加安全模型的 MCP 服务器 | **Apache-2.0** | `pytossinvest` |
`uv` 工作空间单仓库,因此它们在同一仓库中单独构建和部署。
```bash
# 测试 — 无需实时密钥
uv run --package pytossinvest --extra dev pytest pytossinvest/tests # 59 passing
uv run --package pytossinvest-mcp pytest pytossinvest-mcp/tests # 179 passing
```
更多文档请见 [`docs/claude/`](docs/claude/) — [API 参考](docs/claude/tossinvest-open-api.md) · [SDK 内部结构](docs/claude/pytossinvest-sdk.md) · [MCP 安全模型](docs/claude/pytossinvest-mcp.md).
---
## 状态 & 免责声明
- **提供中** — 托斯开放 API 可在 WTS `设置 > Open API` 中 발급密钥。限额·政策·端点可能会在未预先通知的情况下更改。参考文档是快照,实际以 `openapi.json` 为准。
- **使用个人密钥操作个人账户的工具**。不提供代他人进行交易或付费交易信号服务(不仅规避监管,也是刻意避免)。
- 投资判断及其结果完全由个人负责。
## 许可证
SDK(`pytossinvest`)= **MIT** · MCP 服务器(`pytossinvest-mcp`)= **Apache-2.0**。请参考每个包目录下的 `LICENSE` 文件。