内容
# oanda-mcp
MCP 服务器适用于 [Oanda v20 REST API](https://developer.oanda.com/rest-live-v20/introduction/)(外汇/CFD 交易):账户状态、K线、实时定价、订单簿、订单、交易、仓位和交易历史。它默认为练习环境,交易(写入)工具除非显式启用,否则不注册 - 连接到默认配置的客户端无法看到或调用它们。
## 功能
- **设计为只读** — 22 个读取工具涵盖账户、市场数据、定价、订单、交易、仓位和交易历史;7 个写入工具仅在设置 `OANDA_MCP_ENABLE_TRADING` 时存在。
- **默认练习环境** — 通过设置 `OANDA_ENV=live` 选择实时环境。
- **精简响应** — 工具返回交易者操作的字段(价格、单位、盈亏、时间戳),而不是原始 API 转储;列表工具接受 `limit` 参数。
- **保留 v20 约定** — 价格和货币价值为十进制字符串,时间戳为 RFC3339,单位为有符号(正 = 多,负 = 空)。
- **凭证保留在环境中** — token 仅在 `Authorization` 头部传输,错误消息从不回显头部或凭证值。
- **速率限制感知** — HTTP 429 响应重试一次,遵守 `Retry-After`。
## 工具
### 读取工具(始终注册)
| 工具 | 描述 |
|---|---|
| `list_accounts` | 列出为配置的 API token 授权的账户 |
| `get_account` | 配置账户的完整状态,精简至摘要级别 |
| `get_account_summary` | 轻量级账户摘要:余额、净值、保证金空间 |
| `list_account_instruments` | 账户可交易的工具,包含点差位置、显示精度、交易规模限制和保证金率 |
| `get_account_changes` | 从交易 ID 开始轮询订单/交易/仓位变化 |
| `get_candles` | 任意粒度(S5 至每月)的工具 OHLC 蜡烛 |
| `get_order_book` | 当前价格周围的聚合待处理订单簿快照 |
| `get_position_book` | 当前价格周围的聚合开仓簿快照 |
| `get_pricing` | 一个或多个工具的当前买入/卖出/价差 |
| `get_latest_candles` | 每个工具/粒度规范的最新蜡烛 |
| `list_orders` | 账户订单,可按工具和状态过滤 |
| `list_pending_orders` | 账户上的每个待处理订单 |
| `get_order` | 通过 ID 或客户端分配的 ID 获取单个订单 |
| `list_trades` | 账户交易,可按工具和状态过滤 |
| `list_open_trades` | 每个开仓交易,附带止盈/止损订单 |
| `get_trade` | 通过 ID 或客户端分配的 ID 获取单个交易 |
| `list_positions` | 每个工具的每个历史仓位,带有生命周期盈亏 |
| `list_open_positions` | 至少有一个开仓交易的仓位 |
| `get_position` | 账户在一个工具上的仓位 |
| `list_transactions` | 时间范围的交易页面链接(使用 `get_transactions_range` 获取页面) |
| `get_transaction` | 通过 ID 获取单个交易 |
| `get_transactions_range` | 包含 ID 范围的交易 |
### 写入工具(仅在设置 `OANDA_MCP_ENABLE_TRADING` 时注册)
| 工具 | 描述 |
|---|---|
| `configure_account` | 更改账户别名和/或账户范围的保证金率 |
| `create_order` | 创建 MARKET/LIMIT/STOP/MARKET_IF_TOUCHED 订单,附带可选止盈/止损/追踪止损 |
| `replace_order` | 原子替换待处理订单(取消 + 创建) |
| `cancel_order` | 取消待处理订单 |
| `close_trade` | 使用市价订单完全或部分关闭开仓交易 |
| `set_trade_orders` | 创建、替换或取消交易止盈、止损和追踪止损 |
| `close_position` | 关闭工具的多头和/或空头仓位 |
## 配置
所有配置均来自环境变量 - 没有配置文件,没有携带机密的标志。
| 变量 | 默认值 | 目的 |
|---|---|---|
| `OANDA_API_TOKEN` | — (必填) | 个人访问 token,作为 `Authorization: Bearer ...` 发送 |
| `OANDA_ACCOUNT_ID` | 首次授权账户 | 操作账户 |
| `OANDA_ENV` | `practice` | `practice`(api-fxpractice)或 `live`(api-fxtrade) |
| `OANDA_MCP_ENABLE_TRADING` | 关闭 | `true`/`1`/`yes` 注册写入工具 |
## 入门
直接从存储库使用 [uv](https://docs.astral.sh/uv/) 运行:
```sh
uvx --from git+https://github.com/florinel-chis/oanda-mcp oanda-mcp
```
服务器默认使用 stdio;传递 `--transport http --host 127.0.0.1 --port 8000` 以提供可流式传输的 HTTP 服务,路径为 `/mcp`。
> **警告:** HTTP 端点**无身份验证** - 任何可以访问端口的人都可以使用您的 `OANDA_API_TOKEN` 的权限调用每个注册的工具。因此,服务器**拒绝绑定非回环 `--host` 除非还传递 `--allow-remote`**;仅在经过身份验证的反向代理或限制访问的网络(例如下面的 Docker 端口映射)后面使用该标志。
### MCP 客户端配置
将服务器添加到 MCP 客户端的配置中(确切的文件位置取决于客户端):
```json
{
"mcpServers": {
"oanda": {
"command": "uvx",
"args": ["--from", "git+https://github.com/florinel-chis/oanda-mcp", "oanda-mcp"],
"env": {
"OANDA_API_TOKEN": "your-token",
"OANDA_ENV": "practice"
}
}
}
}
```
或运行 Docker 镜像(首先构建它,参见下文):
```json
{
"mcpServers": {
"oanda": {
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "OANDA_API_TOKEN", "-e", "OANDA_ENV", "oanda-mcp"],
"env": {
"OANDA_API_TOKEN": "your-token",
"OANDA_ENV": "practice"
}
}
}
}
```
## Docker
```sh
docker build -t oanda-mcp .
# stdio(适用于 MCP 客户端配置)
docker run -i --rm -e OANDA_API_TOKEN oanda-mcp
# 流式 HTTP 访问 http://127.0.0.1:8000/mcp
# (-p 127.0.0.1:8000:8000 将未经身份验证的端点保持在外部接口之外;
# --host 0.0.0.0 指代容器内的接口,需要 --allow-remote -- 端口映射才能工作,因此主机端的绑定保持回环)
docker run --rm -p 127.0.0.1:8000:8000 -e OANDA_API_TOKEN \
oanda-mcp --transport http --host 0.0.0.0 --port 8000 --allow-remote
```
## 安全
- 除非设置 `OANDA_ENV=live`,否则服务器与**练习**环境通信。
- 除非设置 `OANDA_MCP_ENABLE_TRADING`,否则交易工具被隐藏 - 它们从不注册,而只是被拒绝,因此 MCP 客户端无法发现或调用它们。
- HTTP 传输**无身份验证**:任何可以访问端口的人都可以使用您的 API token 的权限调用每个注册的工具 - 读取余额和仓位始终,启用交易时可以下单或平仓。使用您的 API token 的权限。将其绑定到 `127.0.0.1`(stdio 传输没有此类暴露),或如果确实需要远程访问,则使用经过身份验证的代理。
- 订单放置有一个锋利的边缘:API 可以接受订单并在同一响应中取消 - 例如 FOK 市价订单因 `INSUFFICIENT_MARGIN` 或 `MARKET_HALTED` 而被取消。订单工具显示取消交易,因此请始终在将订单视为已成交之前检查。
- 交易杠杆产品存在风险。请自担风险,并在练习账户上测试所有内容。
## 开发
```sh
uv sync
uv run pytest
uv run ruff check .
```
测试是密封的:所有 HTTP 请求都使用 respx 进行模拟,服务器通过内存 FastMCP 客户端进行测试。运行测试不需要凭证或网络访问。手动、只读的烟雾检查针对真实的练习账户位于 `scripts/smoke.py`。
## 许可证
MIT - 请参阅 [LICENSE](LICENSE)。