关于 ctrader-mcp-servers
面向使用 cTrader Local 和 Remote MCP 服务的 Agent,说明如何识别服务、处理单位与行为差异,并依据已记录的问题安全恢复。
主要功能
- 01识别 Local 与 Remote 服务
- 02比较单位和标识符格式
- 03执行操作前后检查
- 04使用脚本计算点值、保证金和汇率
- 05管理带验证及移除条件的问题记录
适用场景
- 01为图表操作或无头交易选择服务
- 02换算止损距离与交易单位
- 03核验订单修改并从错误中恢复
MCP 相关
介绍 cTrader Local 和 Remote MCP 服务的行为与操作方法;工具结构以各服务的 MCP JSON Schema 为准。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ spotware/ ctrader-skills --skill ctrader-mcp-servers安装后在 Claude Code 中输入/ctrader-mcp-servers确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
LICENSE.txtassets/symbol_precision_table.jsonreferences/known-quirks.mdlocal-http-server.mdremote-http-server.mdself-healing-playbook.mdtrader-workflows.mdscripts/conversion_rate.pypip_math.pyposition_sizing.pytiered_margin.pyunits_encoding.py详细介绍
五大关键问题(行内预览)
截至审计日期,以下五个问题影响最大。完整的检测/处理方法/验证修复/移除标准内容位于 references/known-quirks.md;下方各行仅提供链接预览。另请参阅 references/self-healing-playbook.md,了解命名的恢复模式。
| 问题 | 服务端 | 一句话说明 | 链接 |
|---|---|---|---|
| Q-R10 | 远程 | amend_position 中省略某个交易腿会将其移除(而非保留) | Q-R10 |
| Q-R4 | 远程 | MARKET 不接受绝对 SL/TP——使用 relativeStopLoss/relativeTakeProfit(单次调用),或使用 P-REMOTE-MARKET-2STEP(备用方案) | Q-R4 |
| Q-R1 | 远程 | period 枚举有 9 个值,而非 26 个(删除有关细粒度选项的声明) | Q-R1 |
| Q-L2 | 本地 | SL 是绝对价格,TP 是原始点数(get_pending_orders 的行为不对称) | Q-L2 |
| Q-K19 | 两者 | 点值单位与显示值容易混淆——市价单会无提示地成交 | Q-K19 |
自我修复原则
ctrader-remote-mcp 和 ctrader-local-mcp 均按原样发布,其中记录的运行时行为最近一次重新验证是在 2026-05-14,分别针对 rest-proxy 1.0.18(Remote)和 2026-05-14 观察到的本地构建(Local)。在 1.0.18 上,Remote 仍有六项异常处于 ACTIVE 状态(Q-R1、Q-R2、Q-R3、Q-R5、Q-R8、Q-R10)。两项异常的错误消息格式已优化(Q-R4 和 Q-R7 现在返回带有可操作提示的纯字符串错误信封,而不是 JSON 信封——两者的 DETECT 特征都涵盖这两种格式)。一项异常可能已修复(Q-R11——get_deals 传播延迟——在第 1/5 次会话中通过了 Verify-fixed;尚未移除,待再确认 4 次)。本技能说明语义、注意事项和恢复方法;MCP JSON-Schema 是数据结构的唯一准据。本技能中不得重复 Schema 内容。本技能中关于运行时行为的所有说明都带有构建标记——可以是参考文件中的 as-of: 标头,也可以是 references/known-quirks.md 中异常条目的 Observed-on: 行。
记录表中的每项异常都包含自我弃用机制:它包含一个 Verify-fixed 探测(Agent 可运行的会话内检查)和一个 Removal criteria 条件(服务器已修复、应删除该条目的明确信号)。服务器修复后,删除 references/known-quirks.md 中对应的条目即可——这就是全部清理工作。可选后续操作:使用 grep 搜索参考文件中是否有过时的 QUIRK 提示,并将其删除。
如果服务器行为异常(与 MCP JSON-Schema 和记录表均不一致),请勿自行猜测——遵循 references/self-healing-playbook.md。该手册列出预检关卡(报价合理性、方向、SL/TP 方向、交易量步长、仅使用 Schema 字段、pipettes 与显示值检测、必填字段)、飞行后验证规则(每次变更后重新读取;对于 Remote amend_position,务必重新读取,确认 SL 和 TP 两个部分都保留,参见 Q-R10)、错误分类矩阵(Zod / INVALID_REQUEST / 502 uProxy / 纯文本 Local / available:false / truncated / hasMore)、未知异常决策树(从 STOP 到临时记录条目的 4 个步骤),以及命名模式(P-AMEND-SAFE、P-REMOTE-MARKET-RELATIVE(MARKET+SL/TP 的首选方案)、P-REMOTE-MARKET-2STEP(MARKET 上使用绝对价格 SL/TP 时的备用方案)、P-REMOTE-MARKET-RANGE、P-LOCAL-OLDEST-FIRST、P-REMOTE-HISTORY-CHUNK)。
按经纪商扩展的预留接口
本技能的异常记录表使用 Q-B<n> 前缀作为未来按经纪商覆盖项的预留位置(lotSize 差异、品种命名变体、经纪商特定的 SL/TP 行为)。未来的 assets/broker_overrides.example.json 覆盖文件可用于承载这些按经纪商划分的值,而无需重构本技能。本次迭代未发布——只有在经纪商特定差异成为阻塞问题时才按需添加。
工具表面路由:本地 HTTP(ctrader-local-mcp)与远程 HTTP(ctrader-remote-mcp)
绑定的工具表面决定了当前使用的是哪种 cTrader MCP 服务。检查工具名称和响应 DTO 形状,以识别所属类型。在每次与 cTrader 相关的交互开始时应用以下路由规则;在本次会话中缓存结果。
| 服务类型 | 识别特征 | 最适合的用途 | 默认路由规则 |
|---|---|---|---|
本地 HTTP(ctrader-local-mcp) | ping、get_accounts_list、list_charts、listChartIndicators、listPlugins、show_notification、get_server_time;交易量以单位表示;采用 ISO 8601 格式,且必须带 Z;通过字符串名称("EURUSD")标识品种。HTTP 传输绑定到 cTrader 桌面应用。 | 图表、绘图、指标、自选列表、警报、新闻、cBot、UI 通知、多账户操作。 | 任何涉及 UI / 可视化 / cBot / 图表的工作流都路由至此。 |
远程 HTTP(ctrader-remote-mcp) | get_version、get_assets、以整数 symbolId 为键的工具(get_spot_prices(symbolId)、get_trendbars(symbolId));资金响应中包含 moneyDigits 字段;交易量以分表示(1 手外汇 = 10 000 000);价格以 pipette 为单位。HTTP 传输通过远程 REST 代理(rest-proxy)进行。 | 无头交易、广泛扫描品种、追踪止损、MARKET_RANGE、精细粒度的时间框架历史数据。 | 不需要图表 / UI 时路由至此。 |
| 两种表面均已绑定 | 可以看到两种类型的识别特征。 | 视操作而定。 | 按功能选择:绘图 / cBot / 图表使用本地;追踪 SL / MARKET_RANGE / 多品种批量报价 / 精细粒度时间框架使用远程。 |
两个服务之间的单位约定
两个服务对相同交易概念采用不同的单位和标识符类型;将 Local 值传给 Remote(或反过来)会悄无声息地导致数量、价格错误或架构校验失败。
| 维度 | Local HTTP 编码 | Remote HTTP 编码 | 转换脚本 |
|---|---|---|---|
| 交易量 | 单位(整数;外汇通常为 1 手 = 100 000 单位,但取决于经纪商 — 始终读取 get_symbol_details.lotSize)。 | 分(整数;1 手外汇 = 10 000 000 分)。 | scripts/units_encoding.py lots-to-units / lots-to-cents |
| 价格 | 显示值(例如,1.21345)。 | 点值(整数;除以 10^pipDigits 即为显示值)。 | scripts/pip_math.py(支持双向转换) |
| 货币金额(余额、佣金、掉期、盈亏) | 显示值(例如,12345.67)。 | 以 10^moneyDigits 为单位的整数(响应中的 moneyDigits 字段;通常为 2)。 | scripts/units_encoding.py display-money / parse-money |
| 时间戳 | ISO 8601 格式,必须带 Z 后缀(2026-01-15T14:30:00Z)。 | expirationTimestamp 使用纪元毫秒(自 rest-proxy 1.0.13 起仅支持整数);历史窗口端点可使用任一格式。 | Local 原样传递;Remote 请检查字段类型。 |
| 商品标识符 | 字符串名称("EURUSD"、"XAUUSD")。 | 整数 symbolId(通过 get_symbols 解析,并在会话期间缓存)。 | 不适用(按 ID 查找) |
place_*_order / amend_order 中的止损 / 止盈 | 点差整数(stopLossPips、takeProfitPips)。 | 绝对价格(stopLoss、takeProfit)。 | scripts/pip_math.py pips-to-price / price-to-pips |
止损和止盈:点数距离与绝对价格
下单工具将 SL / TP 设为距离入场价的点数;持仓修改工具将 SL / TP 设为绝对价格。具体约定取决于调用的工具,而非服务器。
| 工具 | 服务器 | SL / TP 形式 |
|---|---|---|
place_market_order, place_limit_order, place_stop_order, place_stop_limit_order | Local | 点数距离(stopLossPips, takeProfitPips)。 |
amend_order(挂单) | Local | 点数距离(stopLossPips, takeProfitPips)。 |
amend_position(未平仓持仓) | Local | 绝对价格(stopLoss, takeProfit)。 |
create_order | Remote | 绝对价格(stopLoss, takeProfit)。关于 MARKET 订单的 SL / TP 拒绝,请参阅 references/remote-http-server.md(P-REMOTE-MARKET-2STEP)。 |
amend_order | Remote | 绝对价格(stopLoss, takeProfit)。 |
amend_position | Remote | 绝对价格(stopLoss, takeProfit)。 |
close_position | Both | 不适用(无 SL / TP 参数)。 |
当用户说“SL 比入场价低 30 点”时,运行 scripts/pip_math.py,将其转换为目标工具所需的形式。输入:--pip-size <float> --digits <int> --reference-price <float> --pips <int>。输出:{"absolute_price": <float>, "pip_size_used": <float>}。该脚本会处理两个方向。
动态杠杆保证金计算
经纪商采用动态杠杆档位:当敞口超过档位上限时,杠杆会降低。所需保证金按档位分别计算后求和。无论交易品种是什么,档位敞口量都以 USD 表示;所得 USD 保证金随后会转换为账户币种。
示例。 账户币种为 USD。订单:做多 1 000 000 EURUSD,价格为 1.21345。USD 名义价值 = 1 000 000 × 1.21345 = 1 213 450 USD。杠杆档位:最高 1 000 000 USD 为 1:500,1 000 000 至 5 000 000 USD 为 1:200,超过 5 000 000 USD 为 1:100。保证金 = (1 000 000 / 500) + (213 450 / 200) = 2 000 + 1 067.25 = 3 067.25 USD。
调用 scripts/tiered_margin.py compute,即可针对任意档位曲线进行计算。输入:--volume-base-units <int> --quote-rate-usd <float> --tiers '[{"upper":1000000,"leverage":500},{"upper":5000000,"leverage":200},{"upper":null,"leverage":100}]'。输出:{"margin_usd": <float>, "per_tier_breakdown": [...]}。使用 scripts/conversion_rate.py compute-chain 将 USD 保证金转换为账户币种。
货币转换:报价货币与账户货币
当交易品种的报价货币与账户货币不同时,服务返回的每个金额(佣金、隔夜利息、已实现盈亏、点值、保证金)都需要通过一条即期汇率链进行转换。例如:EUR 账户的 USDJPY 盈亏需要经过 JPY -> USD -> EUR(使用 USDJPY 和 EURUSD);NZD 账户的 AUDCAD 盈亏需要经过 CAD -> USD -> NZD,或者直接经过 AUD -> NZD。cTrader 后端会构建可用的最短汇率链;使用 scripts/conversion_rate.py 在本地复现此逻辑。
调用 scripts/conversion_rate.py compute-chain 计算汇率。输入:--from-asset <CCY> --to-asset <CCY> --quotes '{"EURUSD":1.0850,"USDJPY":150.3,...}'。输出:{"rate": <float>, "chain": ["EURUSD","USDJPY",...], "warnings": [...]}。通过 get_spot_prices 预先获取报价映射:Local 每次调用一个交易品种,Remote 则使用 get_spot_prices(symbolId:[...]) 批量获取。
对冲账户与净额结算账户
对冲账户允许同一交易品种同时持有多头和空头头寸(各自拥有一个 positionId)。净额结算账户会将它们合并:开立反向头寸会自动平仓(或部分平仓)已有头寸,以形成净头寸。开立对冲的第二笔交易前,读取现有头寸和账户的对冲模式(可在 get_balance 和账户信息响应中查看);如果账户采用净额结算,则无法“开立对冲”——应向用户说明这一点,并建议调整止损或完全平仓。
强制平仓与保证金水平
当保证金水平 =(净值 / 已用保证金)× 100%降至强制平仓水平或以下时,经纪商会强制平仓。强制平仓水平通常为 50% 或 30%,由经纪商设定。存在两种策略:公平策略(平掉占用保证金最多的单个头寸)和智能策略(平掉足以使保证金水平恢复至强制平仓水平以上的最少头寸)。增加风险敞口前,读取当前净值和已用保证金;如果(净值 − 新增所需保证金)/ 开仓后已用保证金 × 100%低于强制平仓水平的 2 倍,则在继续前警告用户。
隔夜利息计提时间
隔夜利息(隔夜融资费用)在经纪商服务器时间的结转时点计提(通常为服务器时间 23:59:59)。许多经纪商会在周三收取三倍隔夜利息(周三 -> 周四的结转会计入周末的起息日价值,适用于外汇等 T+2 交割的工具)。按持仓周期预估隔夜利息时,对周期内的每个周三乘以 3。直接读取 get_positions 和 get_deals 响应中的隔夜利息和佣金数值(这些数值由服务器计算);不要根据费率表重新推算。
可组合的交易工作流
references/trader-workflows.md 中按步骤介绍了七种端到端交易工作流。W0(会话启动)会在会话开始时自动运行一次;W1–W6 则由用户意图触发。当用户请求符合任一触发条件时,请阅读 references/trader-workflows.md 并遵循相应流程,不要从头自行发挥。
- W0 — 会话启动 — 在会话开始时自动运行;识别服务系列,探测实时构建版本,从
assets/symbol_precision_table.json缓存品种精度基准,解析当前活动账户,并设置幂等键前缀。无需用户触发。 - 按风险百分比计算仓位 — 当用户询问“买入/卖出多少”“止损距离为 N 点时的仓位”“这笔交易承担账户 X% 的风险”,或任何同时提及风险比例和止损距离的句子时,选择此流程。
- 交易前简报 — 当用户询问“我该交易 X 吗”“入场前给我看看 X 的概况”“X 现在是什么情况”,或将品种详情、价格和近期历史记录请求合并为一个问题时,选择此流程。
- 交易成本比较 — 当用户询问“A 和 B 哪个交易成本更低”“比较不同品种的点差/佣金/隔夜利息”,或按成本对可交易工具进行排序时,选择此流程。
- 下单并在图表上标注风险/收益 — 当用户询问“下单并在图表上显示”“在 EURUSD 上绘制风险/收益比”,且已绑定 Local HTTP 服务时,选择此流程(此工作流需要绘图功能)。
- 多窗口历史数据回填 — 当用户请求的 K 线数量超过单次
get_trendbars调用的返回上限时,选择此流程(Local 的上限为 1000),例如“给我 5000 根 XAUUSD 的 H1 K 线”或“显示过去一年的 D1 K 线”。 - 安全平仓 — 当用户询问“全部平仓”“取消我的所有订单”“清空我的持仓”,或要求批量关闭一个或多个品种的待处理订单和未平仓头寸时,选择此流程。
特定服务的参考文件
当已绑定的工具接口包含 Local HTTP 工具(ping、get_accounts_list、list_charts、listChartIndicators、listPlugins、show_notification、get_server_time)时,请阅读 references/local-http-server.md,了解 Local 的功能映射、编码规则、分页上限、标识符类型、活动图表定位、绘图对象锚点要求以及破坏性操作检查清单。
当已绑定的工具接口包含 Remote HTTP 工具(get_version、get_assets、以整数 symbolId 为键的工具、响应中的 moneyDigits)时,请阅读 references/remote-http-server.md,了解 Remote 的功能映射、编码规则、包含 9 个值的 period 枚举、服务端校验、timeInForce 语义、dealStatus 枚举,以及 get_symbols 的缓存规则。
当两种接口都已绑定时,请阅读两个文件。
内置脚本
复杂计算位于 scripts/ 中。当计算超出一次乘法或加法时,请调用脚本。所有脚本仅接受 CLI 标志(非交互式),将 JSON 输出到 stdout,将诊断信息输出到 stderr,并通过 --help 提供说明。
| 脚本 | 用途 | 调用方式 | 输出格式 |
|---|---|---|---|
scripts/pip_math.py | 在 pip 距离与绝对价格之间进行转换(显示值;在解码 pipette 后,可处理两个服务的编码方式)。 | python scripts/pip_math.py pips-to-price --pip-size 0.0001 --digits 5 --reference-price 1.0850 --pips 30 | {"absolute_price": 1.08800, "pip_size_used": 0.0001} |
scripts/position_sizing.py | 根据风险百分比或风险金额目标计算订单规模,并计入 pip 价值以及报价货币 -> 账户货币的转换。 | python scripts/position_sizing.py from-risk-percent --balance 10000 --risk-pct 1 --sl-pips 30 --pip-value-per-lot 10 --conversion-rate 1.0 | {"units": 33333, "cents": 3333333, "risk_currency_amount": 100.0, "warnings": []} |
scripts/tiered_margin.py | 根据分层曲线复现 cTrader 的动态杠杆保证金公式。 | python scripts/tiered_margin.py compute --volume-base-units 1000000 --quote-rate-usd 1.21345 --tiers '[{"upper":1000000,"leverage":500},{"upper":5000000,"leverage":200},{"upper":null,"leverage":100}]' | {"margin_usd": 3067.25, "per_tier_breakdown": [...]} |
scripts/conversion_rate.py | 构建两个货币之间最短的即期汇率转换链。 | python scripts/conversion_rate.py compute-chain --from-asset JPY --to-asset USD --quotes '{"USDJPY":150.3}' | {"rate": 0.006653, "chain": ["USDJPY"], "warnings": []} |
scripts/units_encoding.py | 在显示手数与各服务的线路编码(units / cents)之间转换;在显示金额与 moneyDigits 整数之间转换。 | python scripts/units_encoding.py lots-to-cents --lots 0.1 --lot-size 100000 | {"cents": 1000000} |
下单后验证循环
任何修改操作(place_*_order、create_order、amend_order、amend_position、close_position、cancel_order)后,重新获取受影响的实体(get_positions、get_pending_orders 或 get_position_details),并验证成交量、方向、入场价格(针对已成交订单)、SL、TP 和 dealStatus 是否符合用户表达的意图。如果任何值不匹配,请确定不匹配的类别:
- 编码错误 -> 重新运行
scripts/units_encoding.py或scripts/pip_math.py,并使用修正后的输入重试。 - 经纪商拒绝(
dealStatus: REJECTED/INTERNALLY_REJECTED/ERROR)-> 向用户说明服务器响应中的拒绝原因,然后停止。
不要仅因调用未抛出异常就认定订单已成交。