OFFCODEDOCS打开平台

公开 API

四个只读路由,无需密钥和 cookie,使用 聚合器(CoinGecko、CoinMarketCap)和市场库(CCXT)期望的字段名。这些接口供程序自动读取,可用于构建仪表盘、为指数提供数据或核对价格。此 API 中没有下单路由——这里的任何内容都不会移动资金,也不需要账户。

基础与约定

一切挂在 https://offcode.pro/api/public/ 之下,只接受 GET,返回 application/jsonticker_id 形如 BASE_TARGETBTC_USDT):下划线前为基础币,后为计价币,大写字母和数字,每侧 2 到 15 个字符。符号不符合该格式的交易对不予发布。

每个数字都以 十进制字符串 传输,绝不用浮点数——八位小数的币经过 float 会丢失小数。时刻为自 Unix 纪元起的毫秒数。

路由返回内容参数
GET /pairs此数据源覆盖的每个交易对,各自带有价格来源
GET /tickers现货交易对的价格、24 小时成交量、最高价、最低价和买卖双边
GET /orderbook单个交易对的订单簿ticker_id · depth
GET /trades单个交易对的最近成交,最新在前ticker_id · type · limit
GET /historical_trades/trades 相同——两个名字,同一实现相同

交易对 — /pairs

此数据源覆盖内容的完整列表,也是其他路由的门户:不在这里的 ticker_id 在订单簿和成交上都返回 404。kind 区分平台的现货市场(spot)与永续(perp);同一名称同时服务两者时,归现货。price_source 在条目本身说明数字来自哪里。

GET /api/public/pairs
[
  { "ticker_id": "BTC_USDT", "base": "BTC", "target": "USDT", "kind": "spot", "price_source": "offcode-perp" },
  { "ticker_id": "1000PEPE_USDT", "base": "1000PEPE", "target": "USDT", "kind": "perp", "price_source": "offcode-perp" }
]

行情 — /tickers

每个 spot 交易对的价格、24 小时成交量、最高价、最低价和买卖双边。perp 交易对不包含在内:这是聚合器标准所描述的切片。

GET /api/public/tickers
[
  {
    "ticker_id": "BTC_USDT", "base_currency": "BTC", "target_currency": "USDT",
    "last_price": "…", "base_volume": "…", "target_volume": "…",
    "bid": "…", "ask": "…", "high": "…", "low": "…", "timestamp": 1756800000000
  }
]
ticker_id交易对,形如 BASE_TARGET
base_currency · target_currency分别列出交易对的基础币和计价币。
last_price永续合约上的最新成交价。
base_volume以基础货币计的 24 小时成交量,取交易场所发布时的测量值。只有在其缺失时,路由才用 target_volume 除以 last_price 并向下截断到 8 位小数——这是明确声明的计算值,不是交易所给出的数字。
target_volume以计价货币计的 24 小时成交量,来源原始值。
bid · ask两者相等,且都等于永续合约的中间价,并非订单簿中的买一价和卖一价。见 数据来自哪里
high · low最近 24 小时的最高价和最低价。
timestamp读取时刻,自 Unix 纪元起的毫秒数。

订单簿 — /orderbook

单个交易对的订单簿。bidsasks[price, size] 数对,均为十进制字符串,最优价在前。timestamp 是来源的时钟,不是我们的:用本地时钟会让过期的订单簿冒充新鲜的。

depth 可选,每侧最多 100 档。省略时返回上限:100。更大的请求不会被拒绝——而是截断到 100。

GET /api/public/orderbook?ticker_id=BTC_USDT&depth=100
{
  "ticker_id": "BTC_USDT",
  "timestamp": 1756800000000,
  "bids": [["…", "…"], ["…", "…"]],
  "asks": [["…", "…"], ["…", "…"]]
}

成交 — /trades 与 /historical_trades

单个交易对的最近成交记录,最新在前。两个路由是同一实现、同一缓存:聚合器标准要求 historical_trades,CCXT 通常请求 trades,这样就绝不会有一天二者答案不同。

type 可选(buysell,按主动方),limit 最多 100,同样是截断而非拒绝。省略 type 返回双边,省略 limit 返回上限:100。trade_id 是派生的——时刻、方向、价格和数量——同一笔成交在两次读取间保持稳定,它不是交易场所自己的成交标识。

GET /api/public/trades?ticker_id=BTC_USDT&type=buy&limit=100
[
  { "trade_id": "…", "price": "…", "base_volume": "…", "target_volume": "…", "trade_timestamp": 1756800000000, "type": "buy" }
]

数据来自哪里

此数据源中的价格、订单簿、成交和 24 小时成交量都来自 永续市场——包括标记为 spot 的交易对。OFFCODE 的现货没有自己的订单簿:它报的是同名永续合约的 中间价。这就是为什么每个 /pairs 条目都带有 price_source:使用数据源的人在数据源本身读取来源,而不是从标签去推断——推断错误。

bid 和 ask 均为同一个中间价。 由于没有独立的现货订单簿可提供买一价和卖一价,这里的 ask − bid 为零。真实订单簿不可能存在零买卖价差,请勿将这两个字段视为同一订单簿的买一价和卖一价。

base_volume永续合约 以基础货币计的 24 小时成交量,取交易场所发布时的测量值。只有在其缺失时,路由才用 target_volume 除以 last_price 并向下截断到 8 位小数——这是明确声明的计算值,不是交易所给出的数字。

只有存在同名可交易市场时,交易对才会发布:发布就是承诺服务,从 /pairs 出来的 ticker_id 必须紧接着在订单簿和成交上能给出答复。没有可交易对的托管币种不进入数据源,在交易场所名称带乘数因子的交易对也不进入——1000PEPE_USDT 永续按原样发布,绝不会作为 PEPE_USDT

限制、缓存与 CORS

每个 IP 每分钟 600 次请求,每条路由各自计算。超出则返回 429。

2xx 响应带 Cache-Control: public, max-age=5;非 2xx 的响应带 no-store,因为一个被缓存五秒的 404 会比刚上市的交易对活得更久,而一个被缓存的 502 会在交易场所已经恢复之后仍报告它宕机。

底层上,订单簿每个交易对和深度最多每 350 毫秒 重读一次,成交每个交易对每 1 秒 一次:对交易场所的调用上限由缓存决定,而不是由请求人数决定。失败的读取绝不缓存。

Access-Control-Allow-Origin: *,不带凭据——没有 cookie、密钥或认证头,响应中没有任何个性化内容。

错误

状态码触发情形响应体
400ticker_id 不符合格式、type 既非 buy 也非 selldepthlimit 不是整数{"code": "VALIDATION_ERROR", "message": "…"}
404格式正确但不在 /pairs 中的 ticker_id{"error": "UNKNOWN_TICKER"}
429超过该 IP 的请求限制{"statusCode": 429, "code": "RATE_LIMITED", "message": "…"}
502交易场所未响应,或返回了失败{"code": "UPSTREAM_UNAVAILABLE", "message": "…"}

用 502 而不是 500,是有意的:交易场所的故障不是我们的故障,外部读取者需要这个区别来判断是否值得重试。

聚合器与自动化访问

域名位于 Cloudflare 之后。浏览器可以通过;不带 cookie 的命令行调用可能收到验证挑战而不是 JSON——这不是路由在拒绝,而是边缘在询问来者是谁。如果你的机器人需要持续抓取此数据源,请在开启爬虫前申请许可:说明 user-agent、出站 IP 段和预期频率,发送至 联系我们

费率和交易规则不在此 API 中:它们位于 /api/public/fees费用。服务状态见 平台状态