内容
="center">
<="assets/banner.png="Valet — 一个 Brokers和加密货币的代理CP" width">
</p>
<p">
<Valet</strong>MCP工具包,可以在>Interactive Bro 加密货币交易所</strong进行交易,这样您的代理可以,而您决策。
</p="center">
="https:///pedrobraitiading-mcp/actions/workflows/ci.yml"><img src="https://github.com/pedrobraiti/agentic-mcp/actions/workflows//badge.svg" alt集成"></a>
<img src="https:///badge/python-3%2B-bluePython 3.12+">
<imghttps://img.shields.io-MIT-green" alt:MIT">
="https://img.shields.io/badge/status-live--" alt="状态:">
</p>
center">
<img src="assets/demo.gif="Valet演示:$2的 它预览成本、下单" width="</p>
**两个MCP服务器共享一个安全使AI代理(如 Code)能够进行ibkr`** 在 **Interactive Brokers** (美国股票, **按美元金额的 fractional shares** 通过 `cashQty`)和 **`crypto`** 在 **加密货币交易所** (现货,通过CCXT — 持久的API密钥,24/7)。两者都暴露报价、余额、仓位和 **买卖** 在镜像的工具名称下。
* (或卖出)您的技能 例如 [****](https://githubrobraiti/v-trading-skill),决策大脑。该项目仅提供 **可靠的交易管道 默认情况下具有安全> ⚠️ **不是** 默认情况下在* 账户上实时* 交易需要明确的确认。请自担风险。
> **预期。** 服务器是低只需要一个持久的API密钥,24/关 — 它可以无人地运行。 **IBKR** 服务器需要助的 **IB 账户和手动浏览器登录一次**KR不为零售OAuth — IBKR我们的),因此股票完全无人值守大约需要 **30分钟** 每个场地。
## 架构
(端口和适配仅与M;安全防护位于每个订单的路径上;是一个适配器细节```mermaid
A["<br/>( 技能)"]CP 工具|CP 服务器<brMCP) B --> C["Guard<br/>(安全防护)"]
B --> D["市场数据"]
C --> E["CPAPI 适配器"]
D --> E
E -->|REST localhost:5000| F["IBKR 客户端<br/>门户网关"]
F --> G["Interactive Brokers"]
```
```
src/
trading_core/ 共享核心 — 领域模型、端口、交易日志、通用
GuardedBroker 和每个场地的Capabilities合约
ibkr_agent/ IBKR 适配器(cpapi/ 通过客户端门户API)+ `ibkr` MCP 服务器
crypto_agent/ 加密货币适配器(适配器/ccxt/,现货)+ `crypto` MCP 服务器
```
每个场地都是 `trading_core` 之上的一个薄适配器;添加第三个场地是一个新的 `*_agent`
包,而不是对核心的更改。上图仅显示 **IBKR** 服务器。
关键选择的背后原因在 [DECISIONS.md](DECISIONS.md) 中。
## 也支持加密货币交易(第二个MCP服务器)
此存储库是一个 **两个执行服务器的monorepo**,共享一个安全(`tr):上面的IBKR一个 **`crypto`**现货,通过
XT](https://xt/ccxt))。它们是 **独立进程** — ,
自己的工具, — 并且只加密货币在这里,因为IBKR的结构性 **持久的**
(无网每日浏览器登录,无le),一个 **7** 市场,和后面的CCXT,用于~交易所。工具 **KR名称** (_status`,
`,`buy`sell`,`close_position`,`open_orders`,...),因此统一驱动两个。按价值购买的 `cash 通过CCXT的MarketBuyOrder`。 **仅现货** 默认。
```bash 注册加密货币服务器(分开)
mcp add crypto/to/.venv/python.exe -m.server.app
python -.healthcheck 交易所,模式,报价
```
安全KR姿势:** (交易所测试 免费密钥,无是
纸和模拟分支是 **每个场地** (`CRYPTO_ALLOW_LIVE` /
`CRYPTO_DRY_RUN`,两者独立于IBKR门控 — 启动IBKR不会启动加密货币),
而策略限制(`MAX_ORDER_VALUE`,`MAX_DAILY_VALUE`,...)是共享的。参见
[ADR-014](DECISIONS.md) 获取理由和 `.env.example` 中的 `CRYPTO_*` 密钥。
## 为什么 fractional 很重要
大多数零售交易API强制您购买整数股。这项目依赖于IBKR客户端门户API的 `cashQty` 字段,该字段允许您按 **美元金额** 购买(例如 "$50 of AAPL")并获得一个 fractional 头寸 — 解锁了美元成本平均、再平衡和小额账户。有关完整理由,请参见 [DECISIONS.md](DECISIONS.md)。
## 要求
- **Python 3.12- 一个 **Interactive Brokers** 账户,该账户已开通、已充值且为 **IBKR Pro** (API要求,即使使用关联的模拟账户)。
- **Fractional 权限** 已启用:客户端门户 > 交易 > 交易权限 > 股票部分 > 勾选 **"全局(交易分数)"**。
- **IBKR 客户端门户网关** 在本地运行(Java 8)。
- **专用用户名**:仅允许 **券商会话 — 使用相同用户登录 TWS/移动端网关会话
```bash
https://githubrobraitiading-mcp.git
cd agentic-trcp
python -m venv# WindowsShell): & ".\Activate.ps (在策略:Set-Execution Process -Execution# Linux/mac source .venvactivate
pip install ".[dev]"
.example .env 填写 IBKR 等
```
##env`)env.example`密钥:
| | 默认值 ||---|---|---|
|_API_BASE_URLhttps://localhost/v1/api客户端门户端点 |
|_ACCOUNT_ID` | 账户 ID `DU123456模拟账户中 `IBKR_TRADING_MODE` | ` | **仅标签 它 *不账户。是否涉及登录网关;真相是 IB `isPaper` (参见 `session_status` 中的_type`)。 |
| `TRADING_ALLOW | `false 硬锁定:`仅在 `true` 时进行交易 |
TRADING_DRY | `true` **不发送** |
| `TRADING_ALLOW_SHORT` | `false` | 允许 SELL 大于持有仓位(开启空头) |
| `MAX_ORDER_VALUE` | `100.0` | 每订单限制(USD) |
| `MAX_DAILY_VALUE` 累积上限(空上限) |
| `DUPLICATE_WINDOW | ` | 在此窗口相同订单(` = 关闭) 运行
### 网关设置et 与客户端门户网关通信 — 一个KR 提供的 Java 小与您的账户。这是人们经常遇到:
1 [`clientportal.g`](https://activebrokers/clientportal.gw (来自 IBAPI 页面](.interactivebrokers.com/en/trading/))。需要 **Java 8u1922. 将其解压到此的某个位置:
```bash
# Linux/macOS:/run.sh root/conf.yaml
# bin\run.bat root\conf.yaml ```
3. 打开 `localhost:5000` 2FA 登录签名证书警告 — 它是本地且4. ** **"客户端** 且m ibkrcheck` 显示 ` connected=True` 时,您成功了。
在 Valet网关运行;大约每天登录一次 [保持会话活跃](#活跃)登录行为异常登录故障排除故障排除)。
### 注册1.运行并登录的情况下,使用Claude CodeCP服务器:
clcp add ibkr -- /path/to/.venv.exe -m.server.app
```
(或直接运行`.server.app`)
一个新的Claude Code会话中。
2. **检查连接** 随时(关登录的情况下):
```bash
python -m ibcheck # 或:ibkr-healthcheck
显示服务器版本、身份验证状态、账户supportsCash/`supportsF)、余额和报价 保持会话活跃会话过期(无 `/` 约 钟;最多约 24 小时;每日维护约 01:00 断开)KR 不为提供 OAuth,因此重新是手动浏览器登录。
**当MCP服务器会保持自己的** — 背tickle`的生命周期内运行,因此为交互式使用而的进程CP服务器不例如计划作业或),还有一个保持活动:bash
python -_agent.keepalive 或:ibkralive
```
`TICKLE_INTERVAL_SECONDS` 次 `/,并且开时,发出** (ERT] 需要重新:...` )告诉您重新登录。当* 而纪会话时,它们会恢复(无需FA)。
故障排除
https://localhost:` 根本无法 (`ERRUSED` / "拒绝")—甚至不出现页面仅在网,因此这意味着关未启动启动它(`run.bat root\` 在 Windows`bin/run.sh root/conf.yaml` 在 Linux)并打开 — 如果网关停止再次拒绝连接页面加载时,以下才适用。
如果您登录并批准 2FA 但 **没有任何反应** — 页面只是停留在那里,API 仍然处于 `authenticated:false`/`connected:false` 状态(有时 `ssodh/init` 返回 HTTP 500 / `no bridge`):
- **重新启动网关**可以解决。杀进程,重新启动,重新加载 `localhost:,并重新身/私人也有帮助(陈旧的 cookie)。
-不粘**:需要重新登录 **首先** 重新启动网关 —已经运行的网- **如果仍然请退出 IBKR 会话 移动版门户网页 每个用户名只经纪会话重新启动网关。
- 启动器* 版本(2023 年)** 问题 —网关连接到当前 暴露的`session_status`market_status`get_quote`_quotes`_summary`positions`,`portfolio`,`preview_order`,`buy`,`sell`,`close,`stop_order`,`trailing_stop`,`bracket_order`,`order_status`,`wait_for_fill`,`cancel_order`,`open`trade- `get_quotes(symbols)` 在 快照引用整个观察列表每个符号一个` 更便宜 `preview_order(symbol, ...)` 通过 IBKR 的 `whatif` 估算订单的 **保证金影响、佣金和警告** — **不发送** — 这样代理可以在提交前考虑成本。
-` 采用 `` (USD,fractional via `cashQty**或**` (shares,fractional ok)。传递 `limit_price` 以获取 **LIMIT** 订单(默认为市价; `quantity`)。
- `sell` 仅采用 `quantity` (shares,fractional ok);可选 `limit_price` 以获取 LIMIT 卖出。IBKR **不** 允许按美元金额出售 — `cashQty` 仅限买入。
close_position(symbol交易确切数量来关闭% 的仓位。
- `stop_order(symbol, side, quantity, stop_price, limit_price?)` 放置一个 **STOP** (例如止损)— 在 `stop_price` 处触发的市场订单,或如果提供 `limit_price` 则为 STOP-LIMIT。
- `(symbol, side, quantity, trail_amount | trail_percent)` 放置一个 **跟踪止损** — 触发器跟随价格(按美元金额或 %),锁定收益。
- `bracket_order(symbol, quantity, take_profit, stop_loss, ...)` 放置一个入口,附带 **止盈 + 止损退出(OCO)** — 当一个退出成交时,另一个将被取消。
order_status(order_id)` 报告订单的状态、 **数量** 和平均价格 — 在`/`sell` 后来确认成交(仓位在交易后立即滞后)。`wait_for_fill(order_id, timeout_seconds)` 轮询直到成交(或被取消/拒绝),因此代理不会自行协调重试。
- `portfolio()` 返回一个快照:账户摘要 + 开仓 + 总未实现盈亏。
- `trade_history(limit)` 返回最近订单尝试的审计日志(买卖、模拟运行、阻止)— 回答“我的代理做了。
## 使用MCP 注册后自然语言交代理使用工具:
> **您:购买 $50APL。*
代理调用 `="AAPL",=50)` —填充一个al** ≈ 0 股),无需支付的费用(300)。
> **** *"关闭我的 AAPL 头寸。"*
> 代理调用 `close_position(symbol="AAPL")`,它读取确切的数量并出售 100%。
每个工具都返回一个 `{"ok": ..., "data": ...}` 信封。实际执行 fractional 购买的示例(在 IBKR 账户上实时验证):
```json
{
"ok,
"data "order_id": "864501",
"status": "filled",
": "AAPL",
"side": "BUY",
"message": "Bought 0.0066 AAPL Market, Day"
}
}
```
> fractional **购买** 使用 `cashQty`(美元金额)。fractional **卖出** 按份额 *数量* — IBKR 拒绝在卖出时使用 `cashQty`;这就是为什么 `close_position` 存在的原因,它为您解决了确切的数量。
## 安全(默认值)
- **模拟** 默认;**实时** 除非 `TRADING_ALLOW_LIVE=true` 否则阻止。
- **模拟运行** 默认开启(不会发送真实订单)。
- **知道哪个账户是实时的。** `session_status` 和 `portfolio` 直接从 IBKR 的 `isPaper` 报告 `account_type` (`"LIVE"`/`"PAPER"`)— 而不是 `IBKR_TRADING_MODE` 标签,该标签可能与实际登录的账户不一致。实时账户还会返回明确的 **警告**。在交易前检查:真实货币和模拟账户永远无法仅凭配置区分。
- **资金锁定绑定到真实账户,而不是标签。** 在发送之前,防护措施会验证 IBKR 的 `isPaper` 和登录账户,如果配置的 `IBKR_ACCOUNT_ID`,如果一个真实货币账户没有用 `TRADING_ALLOW_LIVE=true` 启动 `IBKR_TRADING_MODE` 与现实不符 — 因此错误的设置无法悄悄交易真实货币。
- **无空:** 除非 `TRADING_ALLOW_SHORT=true`,否则阻止比持有仓位更大的卖空;出口不会。**无反向止损:** 已经处于错误市场一侧的止损(它将立即触发)。
购买** 超过_ORDER_VALUE` 的订单被拒绝是一个支出上限;出口 — 卖出、平仓、止损价值限制,因此可以始终平仓或保护大仓位)。
- 仅在常规交易时间(RTH)内下单,同时考虑 **纽约证券交易所 (通过 `holidays` 库 仅限白名单通过;未知警告 **阻止** 订单。
- 可选 **上限** (`MAX_DAILY_VALUE`) 跨所有购买,在审计日志中 不仅限于每订单。
- **重复订单防护:** 在 `DUPLICATE_WINDOW_SECONDS` 内拒绝相同订单(保护免受超时/重试双重购买)。
- 每次订单尝试(发送、模拟运行或阻止)都被写入本地 **审计日志** (`logs/trades.jsonl`,gitignored)。
- 可选 **符号允许/拒绝列表** (`SYMBOL_ALLOWLIST` / `SYMBOL_DENYLIST`) 限制代理可以交易的宇宙。
保持活动还可以向可选的 **网络钩** (`REAUTH_WEBHOOK_URL`,例如 n/Discord) 发送 POST 请求,当会话需要新鲜登录时 — 单向通知数据,无交易。
## 开发
```bash
python -m pytest - # 测试
python -m ruff check . # 校验
```
参见 [CONTRIBUTING.md](CONTRIBUTING.md) 和 [SECURITY.md](SECURITY.md)。
## 许可证
MIT。