通过 API 集成 — 5 步演练
真实拉数据 + 代码片段。把你的 api key 填上面,每步底下的 fetch / WebSocket 代码直接复制到自己项目。
1
列出可见市场
GET /v1/markets · 首屏渲染市场 Tab
未运行
代码(复制即用)
fetch
const apiKey = "mdc_live_xxx";
const res = await fetch("/api/v1/markets", {
headers: { Authorization: `Bearer ${apiKey}` },
});
const markets = await res.json();
// markets: Array<{ code, label, emoji, count, subMarkets? }>真实数据
点击右上"运行"调用 API,结果会显示在这里
2
拉某市场热门榜
GET /v1/popular · 含 lastPrice / changePct / marketCap / volume24h
未运行
代码(复制即用)
fetch
const res = await fetch(
"/api/v1/popular?market=us&limit=10",
{ headers: { Authorization: `Bearer ${apiKey}` } },
);
const rows = await res.json();
// rows: Array<{
// rank, symbol, name, lastPrice, changePct,
// marketCap, volume24h, logoUrl
// }>真实数据
点击右上"运行"调用 API,结果会显示在这里
3
按关键字搜标的
GET /v1/symbols?q=... · 做搜索框 / 实例选择器
未运行
代码(复制即用)
fetch
const res = await fetch(
"/api/v1/symbols?q=apple&limit=8",
{ headers: { Authorization: `Bearer ${apiKey}` } },
);
const symbols = await res.json();
// symbols: Array<{ symbol, name, market, assetType, marketCap, volume24h, logoUrl }>真实数据
点击右上"运行"调用 API,结果会显示在这里
4
拉历史 K 线
GET /v1/kline · OHLCV 数组,直接喂图表库
未运行
代码(复制即用)
fetch
const res = await fetch(
"/api/v1/kline?symbol=AAPL.US&tf=1d&limit=60",
{ headers: { Authorization: `Bearer ${apiKey}` } },
);
const { candles } = await res.json();
// candles: [{ timestamp, open, high, low, close, volume, preClose, increase, ratio }, ...]
// timestamp 为秒级时间戳,按 timestamp 升序,最后一根可能未收盘
// 直接喂 lightweight-charts / klinecharts真实数据
点击右上"运行"调用 API,结果会显示在这里
5
WebSocket 订阅实时报价
WS /v1/stream · 订阅 topic 收 quote / bar 推送
未运行
代码(复制即用)
websocket
// ───── 基础连接 + 订阅 ─────
const apiKey = "mdc_live_xxx";
const ws = new WebSocket(`/api/v1/stream?api_key=${encodeURIComponent(apiKey)}`);
ws.onopen = () => {
ws.send(JSON.stringify({ action: "subscribe", topics: ["BTCUSDT:quote"] }));
};
// 心跳:每 30s 发 ping,避免空闲 5min 被踢
setInterval(() => ws.readyState === 1 && ws.send('{"action":"ping"}'), 30000);
// ───── K 线图 + 实时价格条 同步推荐写法 ─────
// 同时订 SYMBOL:quote (高频) + SYMBOL:<tf> (画图),用 lastBarSeen 桥接:
let lastBarSeen = null;
const bucketStartTs = (ts, tf) => {
// ts 为秒级时间戳。这里简化版(tf='1m')
const TF_SEC = { '1m':60, '5m':300, '1h':3600, '1d':86400 };
return Math.floor(ts / TF_SEC[tf]) * TF_SEC[tf];
};
ws.onmessage = (ev) => {
const msg = JSON.parse(ev.data);
if (msg.type === "quote") {
// 顶部价格条:高频更新 (~100ms/条)
setPrice(msg.lastPrice);
setChangePct(msg.changePct);
// K 线最右那根活跃 bar:用 lastPrice 同步 c,扩展 h/l —— 跟价格条永远一致
const ts = bucketStartTs(msg.ts, currentTf);
if (lastBarSeen && lastBarSeen.ts === ts) {
lastBarSeen = {
...lastBarSeen,
c: msg.lastPrice,
h: Math.max(lastBarSeen.h, msg.lastPrice),
l: Math.min(lastBarSeen.l, msg.lastPrice),
};
} else {
lastBarSeen = { ts, o: msg.lastPrice, h: msg.lastPrice, l: msg.lastPrice, c: msg.lastPrice, v: 0 };
}
chart.update(lastBarSeen); // lightweight-charts / klinecharts
}
if (msg.type === "bar") {
// bar 推送:完整 OHLV 覆盖,记录 ref 让下一条 quote 能扩展 h/l
lastBarSeen = { ts: msg.ts, o: msg.o, h: msg.h, l: msg.l, c: msg.c, v: msg.v };
chart.update(lastBarSeen);
}
if (msg.type === "error") {
// 按 code switch,不要按 message 文本判断
switch (msg.code) {
case "AUTH_REQUIRED": /* 先 auth 或连接时带 api_key */ break;
case "AUTH_INVALID": /* 重新拿 api_key */ break;
case "INVALID_JSON": /* 检查序列化 */ break;
case "INVALID_MESSAGE": /* 检查 action 字段 */ break;
default: console.error(msg);
}
}
};真实数据
○ 未连接0 条推送
等待推送数据…
API 完整字段说明 → admin /api-explorer · 5 个步骤的源码: apps/web/app/integration/page.tsx