对接马来西亚(Bursa Malaysia)股票数据踩坑:从 yfinance 超时到找个能用的 API
一、背景:为什么马来西亚数据这么难搞
最近帮朋友搭一个东南亚市场的小看盘页,第一站就是马来西亚——Bursa Malaysia(吉隆坡交易所,KLSE),蓝筹像 Maybank、Public Bank、Tenaga Nasional 都在上面。
动手前我先试了三条路:
- yfinance 拉
^KLSE—— 超时是常态,而且林吉特计价、分红拆股字段经常对不上; - Bursa 官方的 API Gateway[^bursa] —— 一看文档是给 Participating Organisations(券商)用的,FIX 协议接入,散户 / 小开发者基本没戏;
- oanor 之类第三方 —— 免 Key 能用,但 2 req/s 硬上限,做实时盘口不够看[^oanor]。
后来在 Telegram 群里有人提了一句 https://pao.stocktv.top/ 覆盖到 MY(countryId=42),去翻了下文档,接口形态是标准 REST + WebSocket,跟我要做的东西对得上,就试了一下。
二、先把"马来西亚"这个参数对齐
StockTV 里国家 ID 的约定是这样(部分):
| 市场 | countryId | 备注 |
|---|---|---|
| 美国 | 1 | NYSE / NASDAQ |
| 日本 | 2 | TSE |
| 印度 | 14 | NSE / BSE |
| 马来西亚 | 42 | Bursa Malaysia (KLSE) |
| 韩国 | — | KRX |
| 新加坡 | — | SGX |
所以后面所有 MY 相关的请求,countryId=42 是固定前缀。
三、几个核心接口的实测
3.1 拉马来西亚股票列表(含实时行情)
import requests
API_KEY = "YOUR_KEY"
BASE = "https://api.stocktv.top"
resp = requests.get(f"{BASE}/stock/stocks", params={
"countryId": 42, # 马来西亚
"pageSize": 10,
"page": 1,
"key": API_KEY,
})
data = resp.json()
for s in data["data"]["records"][:5]:
print(f'{s["symbol"]:12s} {s["name"]:30s} '
f'最新: {s["last"]:.3f} 涨跌: {s["chgPct"]:+.2f}%')
返回里几个字段比较实用:
pid—— 股票唯一 ID,后面查 K 线要靠它last / chg / chgPct—— 最新价 / 涨跌额 / 涨跌幅volume—— 成交量technicalDay—— 日线技术信号(strong_buy / strong_sell之类)
3.2 查单只马股(比如 PBBANK)
requests.get(f"{BASE}/stock/queryStocks", params={
"symbol": "PBBANK",
"key": API_KEY,
}).json()
symbol 直接传 Bursa 那边的代码就行,大小写不敏感但建议大写。
3.3 马来西亚指数(FBMKLCI 等)
requests.get(f"{BASE}/stock/indices", params={
"countryId": 42,
"key": API_KEY,
}).json()
KLCI、创业板指数都在这一层出。
3.4 K 线(日线 / 分钟线)
# pid 从 3.1 的股票列表里拿
resp = requests.get(f"{BASE}/stock/kline", params={
"pid": 12345, # 某只 MY 股票的 pid
"interval": "P1D", # PT5M / PT15M / PT1H / P1D / P1W / P1M
"key": API_KEY,
})
df = pd.DataFrame(resp.json()["data"])
df["time"] = pd.to_datetime(df["time"], unit="ms")
周期枚举是 PT5M / PT15M / PT1H / PT5H / P1D / P1W / P1M,做回测用 P1D,做短线盯盘用 PT5M 就够了。
3.5 马棕油期货(FCPO)—— 这个挺加分
马来西亚数据里有个别的聚合源不太会专门覆盖的点:FCPO( crude palm oil 期货),StockTV 单独给了 /futures/querySymbol?symbol=FCPO。
requests.get(f"{BASE}/futures/querySymbol", params={
"symbol": "FCPO",
"key": API_KEY,
}).json()
做东南亚宏观 / 商品交叉策略的话这个接口省事。
3.6 WebSocket 实时推(Node 为例)
如果只是刷列表,HTTP 轮询也行;但要挂盘口 / 多标的,还是 WS 划算:
const ws = new WebSocket('wss://ws-api.stocktv.top/connect?key=' + API_KEY);
ws.on('message', (raw) => {
const t = JSON.parse(raw);
// t.symbol / t.last / t.chgPct / t.volume
console.log(`[${t.time}] ${t.symbol}: ${t.last}`);
});
延迟官方标 ≤200ms,我自己跑 KL 这边大致体感也是百毫秒级,做看盘页够用。
四、几个踩坑点
⚠️ pid 和 symbol 别混:
/stock/stocks出来的是pid(数字),K 线接口认的是pid,不是symbol。一开始我传 PBBANK 字符串进去,直接 400。⚠️ 林吉特计价不用自己换:返回价已经是 MYR,前端直接渲就行,别再套一层 USD 汇率,会错。
⚠️ 马棕油 FCPO 在 futures 路径下,不在
/stock/*,文档里容易漏看。⚠️ Key 的速率:基础版 100 次 / min,企业版 500 次 / min,挂 WS 的话其实吃的是长连接,不占这个配额。
五、小结
Bursa Malaysia 这块,官方 API 门槛高、免费源又要么延迟要么限流,能找到同时覆盖股票 + 指数 + FCPO、还带 WS 的聚合接口不多。我这小项目最后用的是 StockTV(官网 https://pao.stocktv.top/ ),Key 在 TG 那边找维护者拿:https://t.me/stocktvpaopao ,免费档对个人项目够用,跑通后再看要不要升。
如果你也在接东南亚市场数据,KL / 印尼 / 越南这几个 countryId 可以一起试,接口形态是一样的,换 ID 就行。
参考资料
- https://documenter.getpostman.com/view/42914868/2sB3dLTBM8
- StockTV 多国对接示例(含 MY countryId=42)
更多推荐
所有评论(0)