【零依赖量化数据实战 #13】ETF 盘中实时估值与估算涨跌:2 个 URL 做盯估扫描
摘要:【零依赖量化数据实战 #13】ETF 盘中实时估值与估算涨跌:2 个 URL 做盯估扫描 系列:《零依赖量化数据实战》|零依赖 · 纯 GET · 不 import 任何 SDK 适用:想做 ETF 盘中盯估、估
系列:《零依赖量化数据实战》|零依赖 · 纯 GET · 不 import 任何 SDK
适用:想做 ETF 盘中盯估、估算涨跌异动扫描、估值偏离监控,不想装库或对接多个数据源的开发者
你将得到什么
- 2 个「基金估值」端点的路径、返回字段和语义(估值列表 / 单只估值),照公开文档核对过的,不是猜的
- 一段
scan_gz_movers(threshold)拉全市场估值列表,按估算涨跌幅筛出异动基金 - 字段名容错写法(候选键命中),对字段名不敏感、对形态(list / dict)不敏感
- 完整可复制运行代码,把
你的智兔token换成真实智兔证书即可直接跑
一、两个端点,一张语义表
「盘中盯估」拆成 2 个端点,路径前缀统一 /jh/gz/:
GET https://api.zhituapi.com/jh/gz/gz 估值列表(全市场基金盘中估算值/估算涨跌)
GET https://api.zhituapi.com/jh/gz/zx/{code} 单只基金实时估值(估算净值 + 估算涨跌幅)
鉴权统一 ?token=<你的智兔token>。gz 是全市场估值板(一次性返回所有基金的估算值/估算涨跌),zx 是单只维度,{code} 换成基金代码。估值接口的「估算涨跌幅」是相对昨日单位净值的变动,因此无需再拉历史净值即可扫描盘中异动。
一个实际用法:先用
gz拿到全市场估值板 → 按估算涨跌幅排序/筛出异动 → 再用zx/{code}对其中某只看它的估算净值与估算涨跌细节。这就是盘中盯估。
代码形态提醒:gz/gz 是整板列表(可能上千行),适合扫描;gz/zx/{code} 是单只深度。与 #10 的 ssjy(实时价)不同,估值是「盘中估算净值」,通常在收盘前与实时价有微小偏差——别把两者当同一个数。
二、字段名不固定?用候选键命中
估值接口的返回字段名可能因数据源更新而变化。与其硬编码字段名(改了就全崩),不如用候选键列表命中抽取:
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 scan_gz_movers_safe(board, threshold=1.0):
"""从估值列表中筛出估算涨跌绝对值 >= 阈值的异动基金。"""
ck = ["code", "dm", "fundcode", "jjdm", "symbol"]
zk = ["gz_zdf", "est_chg", "zdf", "chg", "est_zdf", "gsz_zdf", "pchg"]
out = []
for r in board:
if not isinstance(r, dict):
continue
z = _to_float(r.get(_hit_key(r, zk))) if _hit_key(r, zk) else None
if z is not None and abs(z) >= threshold:
out.append((r.get(_hit_key(r, ck)), z))
return out
这样就算数据源把 zdf 改成 gz_zdf,代码不用动。命不中也不报错——只是那只基金取不到涨跌。
三、盘中盯估:全市场估值板扫异动
核心不是「把两个接口都调通」,而是把整板估值归一后做异动扫描。我们关心一件事:估算涨跌幅绝对值超过阈值的基金有哪些。
import sys, time
import requests
TOKEN = "你的智兔token" # ← 换成你的真实智兔token
BASE = "https://api.zhituapi.com"
GZ_ENDPOINTS = {
"gz": ("/jh/gz/gz", "估值列表(全市场)"),
"zx": ("/jh/gz/zx/{code}", "单只基金实时估值"),
}
def fetch(name, code=None, token=TOKEN, timeout=15):
"""拉一个估值端点,返回 (data, err)。"""
path_tmpl, _ = GZ_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 scan_gz_movers(threshold=1.0, token=TOKEN, sleep=0.2):
"""拉全市场估值列表,按估算涨跌幅筛出异动基金。"""
if token == "你的智兔token":
print("[演示] TOKEN 为占位符,下面请求会返回错误码契约;请换成真实 token 后再跑。")
data, err = fetch("gz", token=token)
if err:
print(f" gz (估值列表): 暂不可用:{err}")
return []
rows = [r for r in (data or []) if isinstance(r, dict)]
ck = ["code", "dm", "fundcode", "jjdm", "symbol"]
zk = ["gz_zdf", "est_chg", "zdf", "chg", "est_zdf", "gsz_zdf", "pchg"]
movers = []
for r in rows:
z = _to_float(r.get(_hit_key(r, zk))) if _hit_key(r, zk) else None
if z is not None and abs(z) >= threshold:
movers.append((r.get(_hit_key(r, ck)), z))
print(f" 估值列表 {len(rows)} 条,估算涨跌绝对值 >= {threshold}% 的异动 {len(movers)} 只")
time.sleep(sleep)
return movers
def fund_gz(code, token=TOKEN):
"""单只基金盘中估值深度查看。"""
data, err = fetch("zx", code=code, token=token)
if err:
print(f" zx (单只基金实时估值): 暂不可用:{err}")
return None
print(f" zx (单只基金实时估值): {len(data) if isinstance(data, list) else '聚合对象'} 条/对象")
return data
sleep=0.2 是限频保护。要扫描多只单基估值,把 fund_gz 套一层循环,外面再撑一个更大的间隔即可。
四、代码自验结果
离线自测 6 项全 PASS(真实输出,不联网):
selftest PASS: _hit_key 命中 / 异动筛选 / 空数据兜底 / 字段名不敏感 / 阈值边界 / 数值容错 共 6 项
其中「异动筛选」用的是合成数据(沪深300ETF 估涨 1.8%、中证500ETF 估跌 -0.4%、创业板ETF 估涨 2.3%),断言阈值 1.0 时命中沪深300ETF 与创业板ETF、不命中中证500ETF——这些是逻辑自验用的假数,不是真实估值。
联网跑(占位 token)真实输出:
[演示] TOKEN 为占位符,下面请求会返回错误码契约;请换成真实 token 后再跑。
gz (估值列表): 暂不可用:404 102:Licence证书(你的智兔token)不存在
zx (单只基金实时估值): 暂不可用:404 102:Licence证书(你的智兔token)不存在
两个端点契约一致,单端点失败不影响整体流程、程序友好退出。本文未编造任何估值/估算涨跌数值——换成覆盖该接口的正式证书后重跑,即可打印真实盘中盯估。
五、坑与注意事项
坑 #1:102 不代表路径写对了。 鉴权发生在路由匹配之前。路径故意写错配无效 token,同样返回 102。路径合法性只能靠客户端按白名单自查——本文 2 个路径是照公开文档核对的。实测 HTTP 状态码是 404 而不是 403,重点是看到 102:Licence证书... 就知道是证书问题。
坑 #2:估值是「估算净值」,不是实时价。 gz 给的是盘中估算净值与估算涨跌幅,和 ssjy 的实时交易价/实时涨跌是两回事;收盘前两者会有微小偏差,做套利或精确对账时要分清。
坑 #3:估算涨跌幅已是「相对昨日净值」。 估值接口的估算涨跌幅本身就是相对昨日单位净值的变动,不需要再拉历史净值去算。别多此一举去 lsjz 反推,直接用它扫异动即可。
坑 #4:gz/gz 是整板,量可能很大。 全市场估值板可能上千行,排序/扫描前先想清楚阈值和字段,避免在大列表上做无谓的全量打印。
小结与下篇预告
这篇你拿到了 2 个基金估值端点(估值列表 / 单只估值)、字段名容错抽取写法、以及一个把全市场估值板扫异动的模板,顺带避开了 102 误判、估值≠实时价、重复拉净值、整板过大四个坑。
至此,#09–#13 形成了一条完整的基金分析链:持仓穿透(#09) → 盘中看板(#10) → 技术面回看(#11) → 选基三维度(#12) → 盘中盯估(#13)。
下一篇(#14)正式把视野从基金扩展到 A 股盘面:A 股异动池——用 /hs/pool/ztgc(涨停)/ /hs/pool/dtgc(跌停)/ /hs/pool/qsgc(强势股)/ /hs/pool/cxgc(创新高)/ /hs/pool/zbgc(炸板)5 个异动池端点,做一张日内异动全景扫描看板。
免费领取证书
数据来自 智兔数服(www.zhituapi.com):零 SDK、纯 GET、免费版即可起步。
领取路径:进入 www.zhituapi.com → 点击「请求证书」→「证书获取」→「免费版」(邮箱验证 3 步即可拿到 token)。
把代码里的 你的智兔token 换成你拿到的真实 token,上面的脚本就能直接打印 ETF 盘中估值与估算涨跌数据。
免责声明
本文仅演示公开数据接口的用法,所有代码示例均以占位 token 自验,未含任何真实估值/估算涨跌数据;文中合成数据仅为逻辑自验用途,不构成投资建议,亦不承诺收益。投资决策请基于你自己的判断与风险承受力。