API v1.0 · 只读 · REST + Webhookread-only · REST + Webhook

开发者 API:你的信号,你的 APIDeveloper API: your signals, your API

EA 在你电脑上每一次 AI-1 分析、AI-2 审核、AI-3 持仓判断、实际开平仓,都会同步到 copilotrade.com。这套 API 让你用自己的程序把你自己的这些信号拉走(REST)或实时推到你的服务器(Webhook),再按你自己的规则去币安、OKX、券商或任何平台下单。

Every AI-1 analysis, AI-2 review, AI-3 position check and real open/close your EA makes on your computer is synced to copilotrade.com. This API lets your own program pull your own signals (REST) or receive them in real time on your server (Webhook), then place orders on Binance, OKX, a broker or any platform by your own rules.

概述Overview

TradingView + MT5 EA你电脑上的 EA 跑你的提示词 / 你的 AI KeyEA on your PC runs your prompts / your AI keys
copilotrade.com云桥收到 EA 上报的事件 → 归一化成信号Cloud bridge receives EA events → normalized signals
你的程序Your programREST 拉取 或 Webhook 接收pull via REST or receive via Webhook
任何平台Any platform你自己调币安 / OKX / 券商 API 下单you call Binance / OKX / broker APIs yourself

它是什么:每个会员自己的信号出口。信号就是你的 EA 用你的策略、你的提示词、你的 AI Key 产生的那些决策,本站只是原样转给你。

它不是什么:本站不接任何交易所,不替你下单,不要你的交易所 API Key,不提供平台级「跟单信号源」。信号怎么用、下不下单、下多少,完全由你的程序决定,风险也由你承担。

需要什么:有效会员 + 至少一个绑定了 MT5 并挂着 CopiloTrade-Web EA 的账号。EA 没在跑,就没有新信号。

What it is: a signal outlet for each member's own EA. The signals are the decisions your EA produced with your strategy, your prompts and your AI keys; we only relay them to you unchanged.

What it is not: we do not connect to any exchange, do not place orders for you, never ask for your exchange API keys, and do not provide a platform-level copy-trading feed. How the signals are used, whether and how much to trade, is entirely your program's decision and your responsibility.

Requirements: an active membership and at least one bound MT5 account running the CopiloTrade-Web EA. No running EA, no new signals.

快速开始Quick start

  1. 登录 用户中心 → 展开「开发者 API」→「生成 API Key」。Key 只显示一次,形如 cpt_live_…,请立即保存。
  2. 先测一下:
  1. Sign in to the dashboard → expand “Developer API” → “Create API key”. The key (cpt_live_…) is shown only once; save it right away.
  2. Test it:
curl -H "Authorization: Bearer cpt_live_XXXXXXXX" https://copilotrade.com/api/v1/me
  1. 拉最近的 AI-1 决策:GET /api/v1/signals?type=analysis&limit=20,或者直接配一个 Webhook 地址,让信号一产生就 POST 到你的服务器。
  2. 在你的程序里把 decision(buy / sell / hold)、confidence、levels(估算的入场 / 止损 / 止盈价)映射成你平台上的下单参数。
  1. Pull recent AI-1 decisions: GET /api/v1/signals?type=analysis&limit=20, or configure a Webhook URL so each signal is POSTed to your server as soon as it is produced.
  2. In your program map decision (buy / sell / hold), confidence and levels (estimated entry / SL / TP prices) to order parameters on your platform.

鉴权与限速Authentication & rate limits

所有接口(除 /ping)都要带 Key,两种写法任选:

Every endpoint except /ping requires the key, in either header:

Authorization: Bearer cpt_live_XXXXXXXX
# or
X-API-Key: cpt_live_XXXXXXXX
规则Rule说明Detail
基础地址Base URLhttps://copilotrade.com/api/v1
限速Rate limit每个 Key 每分钟 120 次;超限返回 429 并带 Retry-After 头。另有每 IP 每分钟 300 次。120 requests per minute per key; 429 with a Retry-After header when exceeded. Also 300 per minute per IP.
Key 数量Keys每个用户最多 5 个;撤销立即生效。Up to 5 per user; revocation takes effect immediately.
会员到期Membership expired返回 403 membership_expired,Webhook 同时停推;续费后自动恢复,Key 不变。403 membership_expired; webhooks pause too. Renew and everything resumes with the same key.
返回格式Response shape{ "ok": true, "server_time": 1761900000000, "data": {…} } / { "ok": false, "error": { "code", "message", "message_zh" } }
时间Timestamps*_at 是毫秒 Unix 时间(服务器收到事件的时间);time 是对应的 ISO 8601 UTC;ea_time 是 EA 本机时间原文。*_at are Unix milliseconds (when the server received the event); time is the same in ISO 8601 UTC; ea_time is the EA's local time string.
CORS允许任意来源(Key 在你手里,请勿放进公开网页)。Any origin allowed (keep your key out of public web pages).

接口一览Endpoints

用途Purpose
GET /ping连通性,不用 KeyConnectivity, no key needed
GET /meKey 对应的用户、会员到期、账号列表User behind the key, membership, account list
GET /accounts我的 MT5 账号与 EA 在线情况My MT5 accounts and EA online state
GET /accounts/{login}/status某账号 EA 最新快照:报价、持仓、今日统计、三个 AI 状态Latest EA snapshot: quote, position, today's stats, the three AIs
GET /signals信号列表(游标分页)Signal list (cursor pagination)
GET /signals/latest每个账号最新一条某类型信号Latest signal of a type per account
GET /signals/{id}单条信号One signal
GET /trades实际成交(开仓 / 平仓 / 盈亏)Real trades (open / close / profit)
GET /events信号类型列表List of signal types

机器可读的接口定义:/openapi.json(OpenAPI 3.0,可直接导入 Postman / Swagger UI 生成客户端)。

Machine-readable definition: /openapi.json (OpenAPI 3.0, import into Postman / Swagger UI or generate a client).

GET/api/v1/me
{
  "ok": true, "server_time": 1761900000000,
  "data": {
    "user_id": 123, "username": "alice",
    "membership": { "expire_date": "2027-03-01", "days_left": 120 },
    "key": { "id": 7, "name": "binance bot", "prefix": "cpt_live_Ab1…", "created_at": 1761800000000 },
    "rate_limit_per_min": 120,
    "accounts": [35850021]
  }
}
GET/api/v1/accounts
{ "ok": true, "data": { "accounts": [
  { "account": 35850021, "server": "ICMarkets-Live", "remark": "", "active": true,
    "ea_online": true, "ea_last_seen": 1761900000000, "ea_version": "1.3.14",
    "symbol": "XAUUSD", "ea_state": "running", "has_position": false, "last_signal_at": 1761899000000 }
] } }
GET/api/v1/accounts/{login}/status

EA 每 2~5 秒上报一次的快照(status_at 是上报时间)。ea_online=false 时内容是最后一次看到的,可能已过时。

The snapshot the EA uploads every 2–5 s (status_at is the upload time). When ea_online=false the content is the last seen and may be stale.

{ "ok": true, "data": {
  "account": 35850021, "ea_online": true, "status_at": 1761900000000, "ea_version": "1.3.14", "ea_state": "running",
  "waiting_config": false, "analysis_in_progress": false,
  "account": { "balance": 10234.5, "equity": 10250.1, "free_margin": 9800.0, "currency": "USD", "server": "ICMarkets-Live", "company": "…" },
  "symbol": { "name": "XAUUSD", "bid": 2650.31, "ask": 2650.52, "spread_points": 21, "point": 0.01, "digits": 2, "atr_points": 412, "atr_timeframe": "M15" },
  "ai1": { "model": "gpt-5", "status": "…", "decision": "buy", "confidence": 78, "enabled": true,
           "market_state": "trending", "sl_points": 300, "tp_points": 600, "reason": "…", "next_analysis_in_sec": 540 },
  "ai2": { "model": "…", "status": "…", "decision": "approve", "confidence": null, "enabled": true },
  "ai3": { "model": "…", "status": "…", "decision": "hold", "confidence": 70, "enabled": true },
  "position": { "ticket": 123456, "direction": "buy", "open_price": 2650.5, "lots": 0.1, "sl": 2647.5, "tp": 2656.5, "profit": 12.3, "open_time": "…", "break_even": false },
  "today": { "trades": 2, "wins": 1, "losses": 1, "profit": 15.2 },
  "filters": { "trading_paused": false, "session_blocked": false, "session_status": "…" },
  "license": { "authorized": true, "blocked": false, "days_left": 120 },
  "ai_error": null
} }
GET/api/v1/signals
参数Param说明Detail
accountMT5 账号;不传 = 我的全部账号MT5 login; omit for all my accounts
typeanalysis | review | monitor | trade_open | trade_close | trade_result ;不传 = 全部; omit for all
since_id游标:只返回 id 大于它的,按 id 升序。不传时返回最新的,倒序。Cursor: only rows with id greater than it, in ascending id order. Without it the newest rows are returned in descending order.
since只要这个时间之后的:毫秒 / 秒时间戳或 ISO 字符串Only after this time: ms / s timestamp or ISO string
limit1–200,默认 50, default 50
GET /api/v1/signals?account=35850021&type=analysis&since_id=9000&limit=100

{ "ok": true, "server_time": 1761900000000, "data": {
  "signals": [ { "id": 9001, "type": "analysis", "account": 35850021, "symbol": "XAUUSD", "parent_id": null,
                 "ea_time": "2026-11-01T10:20:50+08:00", "created_at": 1761899250000, "time": "2026-11-01T02:20:50.000Z",
                 "data": { "decision": "buy", "confidence": 78, "market_state": "trending",
                           "sl_points": 300, "tp_points": 600,
                           "levels": { "entry": 2650.52, "sl": 2647.52, "tp": 2656.52 },
                           "reason": "…", "duration_sec": 21.4,
                           "quote": { "bid": 2650.31, "ask": 2650.52, "spread_points": 21, "point": 0.01, "digits": 2 },
                           "atr_points": 412, "atr_timeframe": "M15", "model": "gpt-5" } } ],
  "count": 1, "next_since_id": 9001, "has_more": false
} }
GET/api/v1/signals/latest?type=analysis&account=

每个账号该类型的最新一条(默认 type=analysis)。适合「我现在该做什么」这种查询;要不漏信号请用上面的游标。

The latest signal of that type per account (default type=analysis). Good for “what should I do right now”; to never miss a signal use the cursor above.

GET/api/v1/trades?account=&since=&open=1&limit=

EA 在 MT5 里的实际成交,一笔一行(开仓事件、平仓事件、成交历史核对结果合并而成)。open=1 只看未平的。

Real trades the EA made in MT5, one row per position (open event, close event and history reconciliation merged). open=1 shows open positions only.

{ "ok": true, "data": { "trades": [
  { "account": 35850021, "ticket": 123456, "symbol": "XAUUSD", "direction": "buy", "lots": 0.1,
    "open_price": 2650.5, "sl": 2647.5, "tp": 2656.5, "quote_price": 2650.52, "slippage_points": -2, "actual_rr": 2.0,
    "ai1_confidence": 78, "ai2_verdict": "approve", "magic": 20250101,
    "open_at": 1761899300000, "open_time": "…", "close_at": 1761902000000, "close_time": "…",
    "close_price": 2656.5, "profit": 58.7, "close_reason": "tp", "is_open": false }
], "count": 1 } }

信号类型与字段Signal types & fields

一次完整的交易链路是:analysis(AI-1 看图给出 buy / sell / hold)→ 若不是 hold,review(AI-2 审核 approve / reject)→ approve 则 trade_open(EA 实际下单)→ 持仓期间若开了 AI-3,周期性的 monitor → trade_close(EA 主动平仓)和 / 或 trade_result(仓位消失后从成交历史核对出来的盈亏)。

review 和 trade_open 的 parent_id 指向触发它们的那条 analysis(15 分钟内最近一次);开平仓之间用 data.ticket 对应。

A full cycle is: analysis (AI-1 reads the chart → buy / sell / hold) → if not hold, review (AI-2 approve / reject) → if approved, trade_open (EA places the order) → while in position, periodic monitor if AI-3 is on → trade_close (EA closed it) and/or trade_result (profit reconciled from history after the position disappeared).

parent_id on review and trade_open points to the analysis that triggered them (the latest within 15 minutes); open and close events are matched by data.ticket.

analysis — AI-1 决策— AI-1 decision

字段Field说明Detail
decisionbuy / sell / hold
confidence0–100
market_stateAI 给的市场状态文字,如 trending / rangingAI's market state label, e.g. trending / ranging
sl_points / tp_points止损 / 止盈,点数(MT5 point,XAUUSD 2 位小数时 1 点 = 0.01)Stop loss / take profit in points (MT5 point; for XAUUSD with 2 digits 1 point = 0.01)
levels按上报时报价换算的估算价格:buy 用 ask,sell 用 bid。hold 时为 null。实际成交价以 trade_open 为准。Estimated prices from the quote at upload time: ask for buy, bid for sell. Null for hold. The real fill is in trade_open.
reasonAI 理由(截 300 字)AI reasoning (first 300 chars)
quotebid, ask, spread_points, point, digits
atr_points / atr_timeframeEA 当时的 ATR(点)及其周期EA's ATR (points) and its timeframe at the time
model / duration_secAI-1 模型名、本次调用耗时AI-1 model name and call duration

review — AI-2 审核— AI-2 review

verdictapprove / reject
risk_levelAI-2 给的风险等级文字(low / medium / high)AI-2 risk label (low / medium / high)
reason, model, duration_sec

monitor — AI-3 持仓判断— AI-3 position check

decisionhold / close / modify_sl 等(EA 内部决策名小写)etc. (EA decision names, lower-cased)
confidence0–100
new_sl_points / new_sl_price建议的新止损Suggested new stop loss
position当时持仓快照 ticket, direction, lots, open_price, sl, tp, profitPosition snapshot at the time: ticket, direction, lots, open_price, sl, tp, profit
quote, reason, model, duration_sec

trade_open / trade_close / trade_result

类型Type字段Fields
trade_openticket, direction, lots, price, sl, tp, quote_price, slippage_points, reanchored, actual_rr, ai1_confidence, ai2_verdict, magic
price 是实际成交价,quote_price 是下单瞬间报价;reanchored=true 表示滑点后 SL/TP 按成交价重新锚定。price is the real fill, quote_price the quote when the order was sent; reanchored=true means SL/TP were re-anchored to the fill after slippage.
trade_closeticket, close_reason, close_price?, profit?
EA 主动平仓:tv_ai3(AI-3 平仓)/ friday_close / fill_slip_guard / fill_rr_guard / manual_or_ai3EA-initiated close: tv_ai3 (AI-3) / friday_close / fill_slip_guard / fill_rr_guard / manual_or_ai3
trade_resultticket, close_reason, close_price, profit
仓位消失后从 MT5 成交历史核对出的结果(EA ≥ 1.3.14):sl / tp / so(强平)/ client(手动)/ expert;profit 含手续费与隔夜费。Reconciled from MT5 history after the position disappeared (EA ≥ 1.3.14): sl / tp / so (stop-out) / client (manual) / expert; profit includes commission and swap.

轮询(游标)Polling with a cursor

记住上次拿到的 next_since_id,下次带上 since_id,就不会漏也不会重。第一次可以先 GET /signals?limit=1 拿当前最大 id 作为起点(只要之后的新信号)。建议 5~10 秒轮询一次;更实时请用 Webhook。

Remember the last next_since_id and pass it as since_id next time: nothing is missed or duplicated. On first run GET /signals?limit=1 gives the current max id as a starting point (only signals after now). Poll every 5–10 s; for lower latency use Webhooks.

# Python 3 — poll new AI-1 decisions and hand them to your own order logic
import requests, time

KEY  = "cpt_live_XXXXXXXX"
BASE = "https://copilotrade.com/api/v1"
H    = {"Authorization": f"Bearer {KEY}"}

r = requests.get(f"{BASE}/signals", headers=H, params={"limit": 1}, timeout=10).json()
cursor = r["data"]["next_since_id"]            # start from "now"

while True:
    r = requests.get(f"{BASE}/signals", headers=H,
                     params={"since_id": cursor, "limit": 100}, timeout=10)
    if r.status_code == 429:
        time.sleep(int(r.headers.get("Retry-After", "5"))); continue
    body = r.json()
    if not body.get("ok"):
        print("error:", body["error"]); time.sleep(30); continue
    for s in body["data"]["signals"]:
        d = s["data"]
        if s["type"] == "analysis" and d["decision"] in ("buy", "sell") and d["confidence"] >= 70:
            print(s["id"], s["account"], s["symbol"], d["decision"], d["confidence"], d["levels"])
            # → your_exchange.place_order(symbol_map[s["symbol"]], d["decision"], qty, sl=d["levels"]["sl"], tp=d["levels"]["tp"])
        if s["type"] == "review" and d["verdict"] == "reject":
            print("AI-2 rejected analysis", s["parent_id"])
    cursor = body["data"]["next_since_id"]
    time.sleep(5 if body["data"]["has_more"] is False else 0)

Webhook

在用户中心每个 Key 的「Webhook 推送设置」里填你的 https 地址、勾选要推的事件、开启推送。之后每条信号产生时(EA 上报到服务器的那一刻,通常比 EA 本地晚 1~5 秒)就会 POST 一条 JSON 到你的地址。点「发一条测试」会立刻发一条 type=ping。

In the dashboard, open “Webhook settings” on a key, enter your https URL, pick the events and enable it. From then on each signal is POSTed as JSON to your URL the moment the EA reports it to the server (usually 1–5 s after the EA's local time). “Send test” immediately sends a type=ping.

推送内容Payload

POST {your_url}
Content-Type: application/json
User-Agent: CopiloTrade-Webhook/1.0
X-CopiloTrade-Event: analysis
X-CopiloTrade-Delivery: 55021           # unique per delivery; retries reuse the same id
X-CopiloTrade-Timestamp: 1761899251     # unix seconds, used in the signature
X-CopiloTrade-Signature: t=1761899251,v1=5f3c…e9

{
  "delivery_id": 55021,
  "type": "analysis",                   # same as signal.type; "ping" for the test button
  "key_id": 7,
  "sent_at": "2026-11-01T02:20:51.000Z",
  "signal": { …exactly one item of /signals… },
  "test": true                          # only present on ping
}

签名验证Signature verification

每个 Key 有一个签名密钥 whsec_…(填地址时自动生成,只显示一次,可「重新生成」)。签名 = HMAC-SHA256(secret, "{timestamp}.{raw_body}") 的 hex。请用原始请求体算,不要先解析再序列化;并拒绝时间戳与当前相差超过 5 分钟的请求(防重放)。

Each key has a signing secret whsec_… (created when you first save a URL, shown once, can be rotated). Signature = hex of HMAC-SHA256(secret, "{timestamp}.{raw_body}"). Compute it over the raw request body, never a re-serialized object, and reject requests whose timestamp differs from now by more than 5 minutes (replay protection).

// Node.js (Express) — receive, verify, act
const express = require('express'), crypto = require('crypto');
const SECRET = process.env.CPT_WEBHOOK_SECRET;        // whsec_...
const app = express();
app.post('/copilotrade-hook', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = String(req.get('X-CopiloTrade-Signature') || '');
  const t = (sig.match(/t=(\d+)/) || [])[1], v1 = (sig.match(/v1=([a-f0-9]+)/) || [])[1];
  if (!t || !v1 || Math.abs(Date.now() / 1000 - Number(t)) > 300) return res.status(400).end('bad timestamp');
  const expected = crypto.createHmac('sha256', SECRET).update(`${t}.${req.body}`).digest('hex');
  if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1))) return res.status(401).end('bad signature');
  const evt = JSON.parse(req.body);
  res.status(200).end();                               // ack fast (within 8 s), do the work after
  if (evt.type === 'ping') return;
  if (seen.has(evt.signal.id)) return; seen.add(evt.signal.id);   // idempotency: retries carry the same signal.id
  if (evt.type === 'analysis' && evt.signal.data.decision !== 'hold') {
    // placeBinanceOrder(evt.signal.symbol, evt.signal.data.decision, evt.signal.data.levels) — your code
  }
});
const seen = new Set();
app.listen(8080);
# Python (Flask) — same thing
import hmac, hashlib, time, json
from flask import Flask, request, abort
app = Flask(__name__); SECRET = b"whsec_..."

@app.post("/copilotrade-hook")
def hook():
    sig = dict(p.split("=", 1) for p in request.headers.get("X-CopiloTrade-Signature", "").split(","))
    t = sig.get("t"); v1 = sig.get("v1", "")
    if not t or abs(time.time() - int(t)) > 300: abort(400)
    expected = hmac.new(SECRET, f"{t}.".encode() + request.get_data(), hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, v1): abort(401)
    evt = request.get_json(force=True)
    if evt["type"] == "analysis" and evt["signal"]["data"]["decision"] in ("buy", "sell"):
        pass  # → your exchange call
    return "", 200

重试与停用规则Retries & auto-disable

完整示例:接到币安Full example: wiring to Binance

下面是一个用 Webhook 把 XAUUSD 的 AI-1 决策映射到币安 PAXG/USDT 现货的最小示例(ccxt)。品种映射、仓位大小、是否也要等 AI-2 approve、怎么处理 hold / reject,全是你自己的策略决定,示例只演示接法。

A minimal example that maps XAUUSD AI-1 decisions received by webhook to Binance PAXG/USDT spot via ccxt. Symbol mapping, position size, whether to wait for AI-2 approve, how to handle hold / reject — all of that is your strategy; the example only shows the plumbing.

# pip install flask ccxt
import hmac, hashlib, time, ccxt
from flask import Flask, request, abort

SECRET  = b"whsec_..."
SYMBOLS = {"XAUUSD": "PAXG/USDT"}                      # your mapping
ex = ccxt.binance({"apiKey": "...", "secret": "...", "enableRateLimit": True})   # YOUR exchange keys, on YOUR server
app = Flask(__name__); handled = set()

def verify(req):
    sig = dict(p.split("=", 1) for p in req.headers.get("X-CopiloTrade-Signature", "").split(","))
    if abs(time.time() - int(sig.get("t", "0"))) > 300: abort(400)
    exp = hmac.new(SECRET, f"{sig['t']}.".encode() + req.get_data(), hashlib.sha256).hexdigest()
    if not hmac.compare_digest(exp, sig.get("v1", "")): abort(401)

@app.post("/copilotrade-hook")
def hook():
    verify(request)
    evt = request.get_json(force=True)
    if evt["type"] != "analysis": return "", 200
    s = evt["signal"]; d = s["data"]
    if s["id"] in handled or d["decision"] not in ("buy", "sell") or d["confidence"] < 70: return "", 200
    handled.add(s["id"])
    pair = SYMBOLS.get(s["symbol"])
    if not pair: return "", 200
    usdt = 50                                           # your sizing rule
    price = ex.fetch_ticker(pair)["last"]
    amount = ex.amount_to_precision(pair, usdt / price)
    ex.create_order(pair, "market", d["decision"], amount)
    return "", 200

app.run(port=8080)

错误码Error codes

HTTPerror.code含义Meaning
401missing_key / invalid_key没带 Key / Key 错误或已撤销No key / wrong or revoked key
403membership_expired会员到期,续费后自动恢复Membership expired; resumes after renewal
403account_disabled账号被禁用Account disabled
400bad_account / bad_type / bad_since_id参数不合法Invalid parameter
404account_not_found / not_found该 MT5 不在你账号下 / 没有这条记录或接口MT5 login not yours / no such record or endpoint
429rate_limited / rate_limited_ip超过每 Key / 每 IP 限速,看 Retry-AfterPer-key / per-IP rate limit exceeded, see Retry-After

注意事项Notes

风险提示:这些信号是你自己的 EA 用你自己的提示词、模型和 Key 产生的,本站不保证其正确性、及时性或收益。接到其它平台后的一切下单行为与后果由你自行负责。请先用小仓位或模拟盘验证你的程序。

Risk notice: these signals are produced by your own EA with your own prompts, models and keys; we make no guarantee of correctness, timeliness or returns. Any orders your program places on other platforms, and their consequences, are your sole responsibility. Validate your program with small size or a demo account first.

更新记录Changelog

有问题?客服微信 ajx3158 · Telegram @xauusdgan。Questions? WeChat ajx3158 · Telegram @xauusdgan. 返回用户中心Back to dashboard