【零依赖量化数据实战 #10】场内基金实时报价与清单全貌:4 个 URL 接进盘中看板
摘要:【零依赖量化数据实战 #10】场内基金实时报价与清单全貌:4 个 URL 接进盘中看板 系列:《零依赖量化数据实战》|零依赖 · 纯 GET · 不 import 任何 SDK 适用:想做场内基金(ETF/LOF
系列:《零依赖量化数据实战》|零依赖 · 纯 GET · 不 import 任何 SDK
适用:想做场内基金(ETF/LOF)盘中监控、ETF 全板异动扫描、基金清单维护,不想装库或对接多个数据源的开发者
你将得到什么
- 4 个「场内基金实时/清单」端点的路径、返回字段和语义(单只实时行情 / 全部基金清单 / ETF 行情列表 / LOF 行情列表),照公开文档核对过的,不是猜的
- 一段
fund_board_snapshot()把 ETF 板 + LOF 板 + 全基金清单拉齐,做一张「场内基金全貌」快照;外加fund_realtime(code)对单只基金做深度查看 - 字段名容错写法(候选键命中),对字段名不敏感、对形态(list / dict)不敏感
- 完整可复制运行代码,把
你的智兔token换成真实智兔证书即可直接跑
一、四个端点,一张语义表
「盘中看板」拆成 4 个端点,路径前缀分两类:实时单只走 /fund/,整板/清单走 /jh/。
GET https://api.zhituapi.com/fund/real/ssjy/{code} 单只基金实时行情(价格/涨跌/量)
GET https://api.zhituapi.com/jh/list/all 全部基金清单(静态标的宇宙)
GET https://api.zhituapi.com/jh/hq/etflist ETF 行情列表(整板实时报价)
GET https://api.zhituapi.com/jh/hq/loflist LOF 行情列表(整板实时报价)
鉴权统一 ?token=<你的智兔token>。ssjy 是单只维度,{code} 换成基金代码(文档示例 159001);etflist/loflist/list_all 是整板/全量列表,一次性返回所有标的的报价或清单,适合做扫描。
一个实际用法:先用
jh/hq/etflist拿到整个 ETF 板的实时报价 → 按涨跌排序筛出异动 → 再用fund/real/ssjy/{code}对其中某只做深度查看(jh/list/all则用来维护你自己的基金池子)。这就是盘中看板。
代码形态提醒:/fund/real/ssjy 的 {code} 按文档示例用基金代码(如 159001);/jh/* 同样用基金代码。与 #08 的 /jh/hq/list 不同,本篇用 etflist/loflist 拿分类整板,粒度更细。
二、字段名不固定?用候选键命中
基金实时接口的返回字段名可能因数据源更新而变化。与其硬编码字段名(改了就全崩),不如用候选键列表命中抽取:
def _hit_key(d, candidates):
"""从字典中按候选键名列表命中第一个存在的键。"""
for k in candidates:
if k in d:
return k
return None
def _to_float(v):
"""把可能是字符串/数字/None 的值安全转 float,转不了返回 None。"""
try:
if v is None:
return None
return float(v)
except (TypeError, ValueError):
return None
def summarize_quote(name, data):
"""从实时报价/清单中抽取关键字段做汇总,对字段名不敏感、对形态不敏感。"""
if data is None:
return f" {name}: 无数据"
if isinstance(data, list):
if not data:
return f" {name}: 0 条"
first = data[0] if isinstance(data[0], dict) else {}
code_key = _hit_key(first, ["code", "dm", "fundcode", "jjdm", "symbol"])
name_key = _hit_key(first, ["name", "mc", "jjmc", "shortname"])
price_key = _hit_key(first, ["price", "last", "new", "zxj", "dwjz", "nav", "close", "lastprice"])
chg_key = _hit_key(first, ["change", "zdf", "pct", "zd", "chg", "changepct"])
parts = [f" {name}: {len(data)} 条"]
if code_key:
parts.append(f"首条代码={first.get(code_key)}")
if name_key:
parts.append(f"名称={first.get(name_key)}")
if price_key:
parts.append(f"价格键={first.get(price_key)}")
if chg_key:
parts.append(f"涨跌键={first.get(chg_key)}")
return " | ".join(parts)
if isinstance(data, dict):
keys = list(data.keys())[:6]
return f" {name}: 聚合对象,键={keys}"
return f" {name}: {type(data).__name__}"
这样就算数据源把 dm 改成 jjdm,代码不用动。命不中也不报错——只是那行汇总少一个字段。
三、盘中看板:把整板拉齐做快照
核心不是「把四个接口都调通」,而是把整板数据归一后做异动扫描。我们关心两件事:
- ETF/LOF 整板各有多少只、首条长什么样(确认数据到位)
- 按涨跌绝对值筛出异动标的(阈值可调)
import sys, time
import requests
TOKEN = "你的智兔token" # ← 换成你的真实智兔token
BASE = "https://api.zhituapi.com"
REALTIME_ENDPOINTS = {
"ssjy": ("/fund/real/ssjy/{code}", "单只基金实时行情"),
"etflist": ("/jh/hq/etflist", "ETF 行情列表(整板实时报价)"),
"loflist": ("/jh/hq/loflist", "LOF 行情列表(整板实时报价)"),
"list_all": ("/jh/list/all", "全部基金清单(静态标的宇宙)"),
}
def fetch(name, code=None, token=TOKEN, timeout=15):
"""拉一个实时/清单端点,返回 (data, err)。"""
path_tmpl, _ = REALTIME_ENDPOINTS[name]
url = f"{BASE}{path_tmpl.format(code=code) if code is not None else path_tmpl}"
try:
r = requests.get(url, params={"token": token}, timeout=timeout)
except requests.RequestException as e:
return None, f"网络异常:{e}"
if r.status_code != 200:
return None, f"{r.status_code} {r.text.strip()[:140]}"
try:
payload = r.json()
except ValueError:
return None, f"非 JSON 返回:{r.text[:140]}"
if isinstance(payload, dict):
detail = payload.get("detail") or payload.get("error")
return None, f"业务错误:{detail or list(payload)[:6]}"
return payload, None
def fund_board_snapshot(token=TOKEN, sleep=0.2):
"""拉 ETF 板 + LOF 板 + 全部基金清单,做一张「场内基金全貌」快照。"""
if token == "你的智兔token":
print("[演示] TOKEN 为占位符,下面请求会返回错误码契约;请换成真实 token 后再跑。")
snap = {}
for name in ("etflist", "loflist", "list_all"):
data, err = fetch(name, token=token)
if err:
print(f" {name} ({REALTIME_ENDPOINTS[name][1]}): 暂不可用:{err}")
snap[name] = None
else:
print(summarize_quote(name, data))
snap[name] = data
time.sleep(sleep)
return snap
def fund_realtime(code, token=TOKEN):
"""单只基金实时行情深度查看。"""
data, err = fetch("ssjy", code=code, token=token)
if err:
print(f" ssjy (单只基金实时行情): 暂不可用:{err}")
return None
print(summarize_quote("ssjy", data))
return data
sleep=0.2 是限频保护——3 个整板端点 + 0.2 秒间隔 ≈ 0.6 秒,远在限频内。要监控多只单基,把 fund_realtime 套一层循环,外面再撑一个更大的间隔即可。
四、代码自验结果
离线自测 6 项全 PASS(真实输出,不联网):
selftest PASS: _hit_key 命中 / 列表汇总 / 聚合对象 / 空数据兜底 / 字段名不敏感 / 异动过滤 共 6 项
其中「异动过滤」用的是合成数据(沪深300ETF 涨 1.2%、中证500ETF 跌 -0.5),断言涨跌绝对值 ≥ 0.5 时命中 2 只——这些是逻辑自验用的假数,不是真实行情。
联网跑(占位 token)真实输出:
[演示] TOKEN 为占位符,下面请求会返回错误码契约;请换成真实 token 后再跑。
etflist (ETF 行情列表(整板实时报价)): 暂不可用:404 102:Licence证书(你的智兔token)不存在
loflist (LOF 行情列表(整板实时报价)): 暂不可用:404 102:Licence证书(你的智兔token)不存在
list_all (全部基金清单(静态标的宇宙)): 暂不可用:404 102:Licence证书(你的智兔token)不存在
ssjy (单只基金实时行情): 暂不可用:404 102:Licence证书(你的智兔token)不存在
四个端点契约一致,单端点失败不影响整体流程、程序友好退出。本文未编造任何基金实时报价/清单数值——换成覆盖该接口的正式证书后重跑,即可打印真实盘中看板。
五、坑与注意事项
坑 #1:102 不代表路径写对了。 鉴权发生在路由匹配之前。路径故意写错配无效 token,同样返回 102。路径合法性只能靠客户端按白名单自查——本文 4 个路径是照公开文档核对的。实测 HTTP 状态码是 404 而不是 403(前几篇写的是 403),重点是看到 102:Licence证书... 就知道是证书问题。
坑 #2:etflist/loflist 是整板,别当单只用。 这两个返回的是整个 ETF/LOF 板的实时报价列表(可能几百上千行),适合排序/扫描;要看单只深度,走 fund/real/ssjy/{code}。混用会把整板当单只解析,字段取不到。
坑 #3:清单(list_all)是静态宇宙,报价(etflist)是动态的。 jh/list/all 给的是基金池子(代码+名称),不含实时价;实时价要再走 etflist/ssjy。别指望从清单里拿到报价。
坑 #4:ssjy 的 {code} 用基金代码,不是股票代码。 文档示例为 159001 这类基金代码;别拿 600519 这种股票代码去查基金实时行情,会拿不到数据。
小结与下篇预告
这篇你拿到了 4 个场内基金实时/清单端点(单只实时 / 全基金清单 / ETF 整板 / LOF 整板)、字段名容错抽取写法、以及一个把整板拉齐做盘中快照的模板,顺带避开了 102 误判、整板当单只、清单含报价、基金代码错用四个坑。
下一篇(#11)讲ETF 历史 K 线与均线——用 /jh/hq/lskx(历史 K 线)+ /jh/hq/zxkx(最新 K 线)+ /jh/hq/lsma(历史 MA)+ /jh/hq/zxma(最新 MA)把「盘中看板」升级成「技术面回看」,算最后一日涨跌幅与收盘价相对均线的偏离。
免费领取证书
数据来自 智兔数服(www.zhituapi.com):零 SDK、纯 GET、免费版即可起步。
领取路径:进入 www.zhituapi.com → 点击「请求证书」→「证书获取」→「免费版」(邮箱验证 3 步即可拿到 token)。
把代码里的 你的智兔token 换成你拿到的真实 token,上面的脚本就能直接打印基金实时报价与清单数据。
免责声明
本文仅演示公开数据接口的用法,所有代码示例均以占位 token 自验,未含任何真实基金实时报价/清单数据;文中合成数据仅为逻辑自验用途,不构成投资建议,亦不承诺收益。投资决策请基于你自己的判断与风险承受力。