使用美国行情数据API接口怎么合成动态K线
做行情网站、交易软件或者量化工具,K 线图是绕不开的一块:打开页面要看到历史走势,最右边那一根还要跟着行情实时跳动。这篇教学方案用我们的美国行情数据API接口,以 NASDAQ 的苹果(AAPL)为例,把「历史 K 线 + 实时推送」合成一张动态 K 线图。一共三步,文末有可以直接运行的完整代码。

动态 K 线是怎么合成的
一张会动的 K 线图由两部分数据拼成:
- 历史 K 线:已经走完的那些,用 HTTP 接口一次取回来。
- 动态 K 线:正在走的最新一根,由 WebSocket 持续推送,行情一变就更新。
合成的规则只有一条:推送来的这一根和手里最新一根相比,时间相同就替换,时间更大就新增。下面一步一步来。
准备工作
- 一把密钥。动态 K 线要单独开通,申请密钥时说明即可;没有开通的密钥行情照常推送,只是收不到动态 K 线。
- 接入地址。HTTP 和 WebSocket 的地址写在开发文档的通用规则里,下文用「HTTP 接入地址」「WebSocket 地址」代替。
- 本文的产品是
NASDAQ:AAPL,周期用 1 分钟。换成其它美股(市场代码 NASDAQ、NYSE、AMEX)或其它周期,写法完全一样。
第一步:用 HTTP 接口取历史 K 线
用到的接口是单个产品实时 / 历史 K 线。请求头带 Authorization: 你的密钥,请求写法:
GET /api/mini_list?market=NASDAQ&symbol=AAPL&interval=1min
返回(data 里有很多根 K 线,这里只列出第 1 根):
{
"status": 0,
"interval": "1min",
"market": "NASDAQ",
"code": "AAPL",
"message": "SUCCESS",
"data": "1791316860,333.63,333.63,333.63,333.63,0,606067.78399;…"
}
data 是一个字符串:多根 K 线用英文分号隔开,最新的在前;一根里面的 7 项用英文逗号隔开,顺序固定:
- 时间:Unix 秒,这根 K 线的开始时间
- 收盘价:还没走完的那一根是最新价
- 开盘价
- 最高价
- 最低价
- 备用
- 成交量
顺序是「时间、收、开、高、低」,不是常见的「开、高、低、收」,解析时别放错位置。一页 500 根,要更早的数据就把 page 加 1 往前翻。
第二步:连接 WebSocket 并订阅产品
按连接、订阅与心跳里的写法连接,收到连接成功的消息之后发送订阅命令:
/sub/NASDAQ:AAPL
动态 K 线没有单独的订阅命令,订阅了产品就会和行情一起推送。收到的消息里,Cmd 为 rm 的是行情,Cmd 为 bars 的就是动态 K 线:
{
"Market": "NASDAQ",
"code": "AAPL",
"1": "1791316860,333.63,333.63,333.63,333.63,0,606067.78399",
"5": "1791316800,333.63,333.66,333.79,333.63,0,9470495.048838",
"15": "1791316800,333.63,333.66,333.79,333.63,0,9470495.048838",
"30": "1791316800,333.63,333.66,333.79,333.63,0,9470495.048838",
"1h": "1791315000,333.63,333.615,334.38,333.09,0,12491334.148575",
"1d": "1791244800,333.63,332.28,334.38,330.62,0,28787787.644219",
"1w": "1791158400,333.63,332.815,336.21,330.62,0,60808820.943908",
"1m": "1790812800,333.63,330,336.21,325.81,0,127180831.812139",
"Cmd": "bars"
}
一条消息带 8 个周期,每个字段是这个周期最新的一根 K 线,7 项的顺序和第一步完全相同。推送里的字段名和 HTTP 接口的周期写法不一样,对照如下:
1对应1min(1 分钟)5对应5min(5 分钟)15对应15min(15 分钟)30对应30min(30 分钟)1h对应1h(1 小时)1d对应1day(1 日)1w对应1week(1 周)1m对应1month(1 个月,不是 1 分钟)
连接期间每 10 秒发送一次 /heartbeat/PING 作为心跳。
第三步:把推送合到历史 K 线上
从推送里取出要用的那个周期(本文是字段 1),和手里的 K 线比时间:
- 时间相同:还是同一根,用推送的整根替换它。一根 K 线没走完之前会反复推送,时间不变,收盘价、最高价、最低价、成交量在变。
- 时间更大:上一根已经走完,把推送的这一根加到最后。
行情连续变化时,同一个产品大约每 1.5 秒推送一次;休市时没有推送,K 线自然停住。每次合并之后重画最后一根,K 线图就动起来了。
完整示例代码
下面的代码用 Node.js 22 及以上版本可以直接运行(自带 fetch 和 WebSocket),把开头三项换成自己的即可。接到图表库时:历史数据一次性交给它,之后每合并一次就更新最后一根。
// 运行:node kline.js(Node.js 22 及以上)
const KEY = '你的密钥';
const HTTP_BASE = 'HTTP 接入地址'; // 见开发文档「概览 · 通用规则」,以 /api/ 结尾
const WS_URL = 'WebSocket 地址'; // 同上,最后一段 {key} 换成密钥
const MARKET = 'NASDAQ', SYMBOL = 'AAPL';
const HTTP_INTERVAL = '1min'; // HTTP 接口里的周期写法
const WS_FIELD = '1'; // 推送里对应的字段
// 一根 K 线:「时间,收,开,高,低,备用,量」→ 对象
function parseBar(text) {
const [time, close, open, high, low, , volume] = text.split(',').map(Number);
return { time, open, high, low, close, volume };
}
// 第一步:取历史 K 线。返回里最新的在前,这里倒过来,变成从早到晚
async function loadHistory() {
const url = `${HTTP_BASE}mini_list?market=${MARKET}&symbol=${encodeURIComponent(SYMBOL)}&interval=${HTTP_INTERVAL}`;
const res = await fetch(url, { headers: { Authorization: KEY } });
const text = await res.text();
const body = JSON.parse(text);
if (body.status !== 0) throw new Error('取历史 K 线失败:' + text);
return body.data.split(';').filter(Boolean).map(parseBar).reverse();
}
// 第三步:把推送来的一根合进去。时间相同就替换,时间更大就新增
function merge(bars, bar) {
for (let i = bars.length - 1; i >= 0 && bars[i].time >= bar.time; i--) {
if (bars[i].time === bar.time) { bars[i] = bar; return; }
}
const last = bars[bars.length - 1];
if (!last || bar.time > last.time) bars.push(bar);
}
async function start() {
const bars = await loadHistory();
console.log('历史 K 线', bars.length, '根');
// 第二步:连接、订阅、心跳
const ws = new WebSocket(WS_URL);
let connected = false, heartbeat;
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.Cmd === 'connect' && msg.State === 0) {
connected = true;
ws.send(`/sub/${MARKET}:${SYMBOL}`);
heartbeat = setInterval(() => ws.send('/heartbeat/PING'), 10000);
} else if (msg.Cmd === 'bars' && msg.Market === MARKET && msg.code === SYMBOL && msg[WS_FIELD]) {
merge(bars, parseBar(msg[WS_FIELD]));
const b = bars[bars.length - 1];
console.log(new Date(b.time * 1000).toISOString(), '开', b.open, '高', b.high, '低', b.low, '收', b.close, '量', b.volume, '共', bars.length, '根');
}
};
ws.onclose = () => {
clearInterval(heartbeat);
// 连上之后断开的:过 3 秒重新取历史、重新订阅。一次都没连上多半是密钥或地址不对,不要反复重连
if (connected) setTimeout(() => start().catch(console.error), 3000);
else console.error('没有连上,请检查密钥和地址');
};
}
start().catch(console.error);
常见问题
收不到 Cmd 为 bars 的消息? 先确认密钥开通了动态 K 线(没开通时行情照常推送);再确认是不是休市,产品有新的行情才会推送。
没有开通动态 K 线能不能做? 可以。定时请求第一步的接口:第 1 页的第一根就是正在走的那一根,周期走完之前它会一直变。缺点是没有推送及时,而且每次请求都算一次调用。
断线了怎么办? 订阅只对当前这条连接有效,重连后要重新订阅;断线期间的 K 线重新取一次历史补上。上面的示例代码已经这样处理。
要 10 分钟周期怎么办? HTTP 接口有 10min,推送里没有 10 分钟这个周期,需要的话用第一步的接口定时取。
想同时看很多产品? 一条订阅命令可以带多个产品,用英文逗号隔开,如 /sub/NASDAQ:AAPL,NASDAQ:TSLA。只用少数产品的 K 线时请按产品订阅,不要订阅整个市场,那样数据量很大。
其它国家和市场
HTTP 的 K 线接口和 WebSocket 的订阅命令不分市场,把 market 换成对应的市场代码即可,例如印度 NSE、香港 HK、日本 TSE、韩国 KRX。全部取值见国家与市场参数。想在个股页面加上公司介绍,可以接着看怎么用印度行情数据API接口获取公司介绍。